TypeScript:如何从单键对象联合类型创建映射类型?
需求与问题
假设有如下联合类型定义:
type UpdateUnion = {foo:number} | {bar:string} | {baz: {value1: number, value2: string}};
想要构造出对应的映射类型:
type UpdateFunctions = { foo: (value: number) => void, bar: (value: string) => void, baz: (value: {value1: number, value2:string}) => void };
尝试了以下代码,但仅在联合类型只有一个成员时有效,否则报错Type 'Key' cannot be used to index type 'UpdateUnion':
type KeysOfUnion<T> = T extends T ? keyof T : never; type UpdateFunctions = { [Key in KeysOfUnion<UpdateUnion>]: (value: UpdateUnion[Key]) => void }
解决方案
问题出在UpdateUnion[Key]这一步:因为UpdateUnion是联合类型,当Key是多个键的联合时,TypeScript没法直接确定每个键对应的具体类型。
可以用TypeScript 4.1+支持的映射类型重命名(as子句)来解决,直接遍历联合类型的每个成员,而不是先提取所有键的联合:
type UpdateUnion = {foo:number} | {bar:string} | {baz: {value1: number, value2: string}}; type UpdateFunctions = { [T in UpdateUnion as keyof T]: (value: T[keyof T]) => void };
原理说明
[T in UpdateUnion as keyof T]:遍历联合类型UpdateUnion的每个成员T,把T的键作为映射类型的属性名。T[keyof T]:获取当前成员T对应键的类型,这样每个属性对应的函数参数类型就完全匹配了。
如果需要兼容更早版本的TypeScript,也可以用条件类型提取键值对后再构造:
// 先把联合类型的每个成员转换成 {key: 键名, value: 键值类型} 的形式 type KeyValuePair<T> = T extends { [K in keyof T]: infer V } ? { key: K, value: V } : never; type UpdateFunctions = { // 遍历所有键名 [K in KeyValuePair<UpdateUnion>['key']]: // 提取对应键的value类型 (value: Extract<KeyValuePair<UpdateUnion>, { key: K }>['value']) => void };
两种方式都能得到目标的UpdateFunctions类型,第一种更简洁直观。
内容的提问来源于stack exchange,提问作者Salvo Miosi
相关产品推荐
相关产品推荐

