TypeScript:任意泛型类型的交集实现及相关疑问
解答你的TypeScript类型操作疑问
先看你写的Unificator类型,确实能实现预期效果,下面逐个解答你的问题:
1. 这种映射类型用法是否合法?
合法。这是TypeScript 4.1版本引入的映射类型重映射(as子句)的标准用法:你把T的所有键都重命名为固定的"union",由于多个键对应同一个属性名,TypeScript会自动将这些属性的类型合并为联合类型,最后通过["union"]取出这个合并后的类型。只是这种写法属于偏技巧性的“曲线救国”,不是最直接的实现方式。
2. 更正统的联合类型合并方式
有,直接使用T[keyof T]即可。这是TypeScript中获取对象所有值类型联合的标准写法,比你写的映射类型简洁得多:
export type Unificator<T extends Record<string, unknown>> = T[keyof T]; // 用法和你的原代码完全一致 let u: Unificator<{ a: { foo: "bar" }, b: { bar: "baz" }, c: { answer: 42 } }>; u = { foo: "bar" }; // 合法 u = { bar: "baz" }; // 合法 u = { answer: 42 }; // 合法
3. 能否避免临时的"union"属性?
完全可以,上面的T[keyof T]写法就彻底规避了临时属性,直接一步到位获取所有值的联合类型,这也是最推荐的写法。
4. 实现任意数量类型的交集
要实现多个类型的交集,需要先获取值的联合类型,再通过分布式条件类型+逆变位置特性将联合类型转换为交集类型。具体实现如下:
首先定义一个工具类型UnionToIntersection,用来把联合类型转成交集:
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
原理是:当U是联合类型时,分布式条件类型会逐个将联合分支代入U extends any,生成多个函数类型的联合;而函数参数是逆变位置,TypeScript在推断infer I时会自动取所有分支的交集。
然后基于这个工具实现Intersector:
export type Intersector<T extends Record<string, unknown>> = UnionToIntersection<T[keyof T]>; // 验证你的预期效果 let i: Intersector<{ a: { foo: "bar" }, b: { bar: "baz" }, c: { answer: 42 } }>; i = { foo: "bar", bar: "baz", answer: 42 }; // 合法 // 下面的写法会报错,因为缺少必要属性 // i = { foo: "bar" }; // Error
内容的提问来源于stack exchange,提问作者damix911
相关产品推荐
相关产品推荐

