TypeScript中基于枚举类型实现函数参数类型推断与补全
TypeScript根据第一个参数类型推断第二个参数的实现方案
问题描述
我在开发TypeScript项目时遇到需求:希望函数的第二个参数data能根据第一个参数type实现类型推断与自动补全。
给定类型定义:
enum MessageType { FOO = "FOO", BAR = "BAR", BAZ = "BAZ", } interface DataFoo { type: MessageType.FOO payload: string } interface DataBarOrBaz { type: MessageType.BAR | MessageType.BAZ name: string age: number } type Data = DataFoo | DataBarOrBaz
需要开发的函数结构如下,需为data参数提供自动补全:
function emit<T extends MessageType>(type: T, data: ???) {}
预期效果:传入不同MessageType枚举值时,data自动匹配对应类型并补全字段。但使用Extract工具类型尝试时,针对type为枚举联合类型的接口无法生效——传入BAR/BAZ时data类型变为Omit<never, "type">。请问TypeScript 5.x版本中如何实现该需求?
解决方案
问题核心是Extract<Data, { type: T }>无法正确匹配type字段为联合类型的成员(如DataBarOrBaz),因为Extract会进行严格的字面量类型匹配。以下两种方案可在TypeScript 5.x中解决该问题:
方案一:利用条件类型分布式特性
通过条件类型遍历Data联合类型,筛选出type包含当前T的成员:
type DataForType<T extends MessageType> = Extract<Data, { type: T }> extends never ? Extract<Data, { type: infer U }> extends { type: T | infer _ } ? Extract<Data, { type: U }> : never : Extract<Data, { type: T }>; function emit<T extends MessageType>(type: T, data: Omit<DataForType<T>, 'type'>) {}
方案二:构建类型映射表(可读性更强)
手动创建MessageType到对应数据类型的映射表,通过索引访问直接获取对应类型:
type DataMap = { [MessageType.FOO]: Omit<DataFoo, 'type'>; [MessageType.BAR]: Omit<DataBarOrBaz, 'type'>; [MessageType.BAZ]: Omit<DataBarOrBaz, 'type'>; }; function emit<T extends MessageType>(type: T, data: DataMap[T]) {}
效果验证
两种方案均能实现预期功能:
- 传入
MessageType.FOO时,data自动补全为{ payload: string } - 传入
MessageType.BAR或MessageType.BAZ时,data自动补全为{ name: string; age: number }
内容的提问来源于stack exchange,提问作者Leo Wong
相关产品推荐
相关产品推荐

