我创建了这个游乐场,这里是代码:
type BundlerError = Error;
type BundlerWarning = Error;
export type BundlerState =
| { type: 'UNBUNDLED' }
| { type: 'BUILDING'; warnings: BundlerWarning[] }
| { type: 'GREEN'; path: string; warnings: BundlerWarning[] }
| { type: 'ERRORED'; error: BundlerError }
const logEvent = (event: BundlerState) => {
switch (event.type) {
case 'UNBUNDLED': {
console.log('received bundler start');
break;
}
case 'BUILDING':
console.log('build started');
break;
case 'GREEN':
if(event.warnings.length > 0) {
console.log('received the following bundler warning');
for (let warning of event.warnings) {
warning
console.log(warning.message);
}
}
console.log("build successful!");
console.log('manifest ready');
break;
case 'ERRORED':
console.log("received build error:");
console.log(event.error.message);
break;
}
}
Run Code Online (Sandbox Code Playgroud)
BundlerState 是一个有区别的联合,并且 switch 缩小了类型。
问题是它不能扩展,而且大的扩展 switch 语句非常可怕。
有没有更好的方法可以写这个并且仍然保持好的类型缩小?
你不可以做这个:
const eventHandlers = {
BUNDLED: (event: BundlerState) => event.type // type is not narrowed
// etc,
};
const logEvent = (event: BundlerState) => eventHandlers['BUNDLED'](event);
Run Code Online (Sandbox Code Playgroud)
因为类型没有缩小。
这是我经常使用的一种模式(或其变体)。
type BundlerStatesDef = {
UNBUNDLED: {}
BUILDING: { warnings: BundlerWarning[] }
GREEN: { path: string; warnings: BundlerWarning[] }
ERRORED: { error: BundlerError }
}
type BundlerStateT = keyof BundlerStatesDef
type BundlerStates = { [K in BundlerStateT]: { type: K } & BundlerStatesDef[K] }
type BundlerHandler<K extends BundlerStateT> = (params: BundlerStates[K]) => void
type BundlerHandlers = { [K in BundlerStateT]: BundlerHandler<K> }
Run Code Online (Sandbox Code Playgroud)
使用上面定义的类型,您可以有一个非常符合人体工程学的实现,如下所示:
const handlers: BundlerHandlers = {
UNBUNDLED: params => console.log(params),
BUILDING: params => console.log(params),
GREEN: params => console.log(params),
ERRORED: params => console.log(params)
}
const logEvent = <E extends BundlerStateT>(event: BundlerStates[E]) =>
(handlers[event.type] as BundlerHandler<E>)(event)
Run Code Online (Sandbox Code Playgroud)
贴近你的原始定义,甚至不那么冗长,你可以这样做:
type BundlerError = Error
type BundlerWarning = Error
export type BundlerState =
| { type: 'UNBUNDLED' }
| { type: 'BUILDING'; warnings: BundlerWarning[] }
| { type: 'GREEN'; path: string; warnings: BundlerWarning[] }
| { type: 'ERRORED'; error: BundlerError }
export type BundlerHandlers = { [K in BundlerState['type']]: (params: Extract<BundlerState, { type: K }>) => void }
const handlers: BundlerHandlers = {
UNBUNDLED: params => console.log(params),
BUILDING: params => console.log(params),
GREEN: params => console.log(params),
ERRORED: params => console.log(params)
}
const logEvent = (event: BundlerState) =>
(handlers[event.type] as (params: Extract<BundlerState, { type: typeof event['type'] }>) => void )(event)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
847 次 |
| 最近记录: |