gpt4 book ai didi

typescript - typescript 区分联合的 switch 语句的替代方法

转载 作者:行者123 更新时间:2023-12-04 14:39:37 30 4
gpt4 key购买 nike

我已创建 this playground这是代码:

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;
}
}
BundlerState 是一个有区别的联合,并且 switch 缩小了类型。
问题是它不能扩展,而且大扩展的 switch 语句非常可怕。
有没有更好的方法可以写这个并且仍然保持好的类型缩小?
你不可以做这个:
const eventHandlers = {
BUNDLED: (event: BundlerState) => event.type // type is not narrowed
// etc,
};

const logEvent = (event: BundlerState) => eventHandlers['BUNDLED'](event);
因为类型没有缩小。

最佳答案

这是我经常使用的一种模式(或其变体)。

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> }
使用上面定义的类型,您可以有一个非常符合人体工程学的实现,如下所示:
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)
PLAYGROUND

贴近你的原始定义,甚至不那么冗长,你可以这样做:
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)
PLAYGROUND

关于typescript - typescript 区分联合的 switch 语句的替代方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64092736/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com