【发布时间】:2019-04-09 22:15:36
【问题描述】:
问题
假设我有一些这样的代码:
// Events we might receive:
enum EventType { PlaySong, SeekTo, StopSong };
// Callbacks we would handle them with:
type PlaySongCallback = (name: string) => void;
type SeekToCallback = (seconds: number) => void;
type StopSongCallback = () => void;
在我提供的 API 中,我可以注册这样的回调
declare function registerCallback(t: EventType, f: (...args: any[]) => void);
但我想摆脱 any[] 并确保我不能注册类型错误的回调函数。
解决方案?
我意识到我可以做到这一点:
type CallbackFor<T extends EventType> =
T extends EventType.PlaySong
? PlaySongCallback
: T extends EventType.SeekTo
? SeekToCallback
: T extends EventType.StopSong
? StopSongCallback
: never;
declare function registerCallback<T extends EventType>(t: T, f: CallbackFor<T>);
// Rendering this valid:
registerCallback(EventType.PlaySong, (name: string) => { /* ... */ })
// But these invalid:
// registerCallback(EventType.PlaySong, (x: boolean) => { /* ... */ })
// registerCallback(EventType.SeekTo, (name: string) => { /* ... */ })
这真是漂亮而强大!感觉就像我在使用依赖类型:我基本上在这里为自己编写了一个将值映射到类型的函数。
但是,我不知道 TypeScript 类型系统的全部强度,也许有更好的方法将枚举值映射到这样的类型。
问题
有没有更好的方法将枚举值映射到这样的类型?我可以避免像上面那样非常大的条件类型吗? (实际上我有很多事件,而且有点乱:当我将鼠标悬停在 CallbackFor 上时,VS Code 会显示一个巨大的表情,而我的 linter 真的想在每个 : 之后缩进。)
我很想编写一个将枚举值映射到类型的对象,因此我可以使用T 和CallbackFor[T] 声明registerCallback,但这似乎不是一回事。任何见解都值得赞赏!
【问题讨论】:
标签: typescript types enums dependent-type conditional-types