TypeScript中如何将交叉类型转为联合类型以获取重载函数
TypeScript交叉类型转联合类型实现方案
TypeScript支持将交叉类型转换为联合类型,尤其是你提到的重载函数场景(函数交叉类型),可以通过类型工具实现转换,不过要注意普通对象交叉类型和函数交叉类型的差异。
一、重载函数(函数交叉类型)的转换实现
重载函数在TS里确实是以多个函数类型的交叉形式存在的,要把它拆成联合类型,可以用递归条件类型结合元组转换:
类型工具代码
// 提取重载函数的所有签名到元组 type Overloads<T> = T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; (...args: infer A3): infer R3; (...args: infer A4): infer R4 } ? [(...args: A1) => R1, (...args: A2) => R2, (...args: A3) => R3, (...args: A4) => R4] : T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; (...args: infer A3): infer R3 } ? [(...args: A1) => R1, (...args: A2) => R2, (...args: A3) => R3] : T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2 } ? [(...args: A1) => R1, (...args: A2) => R2] : T extends { (...args: infer A1): infer R1 } ? [(...args: A1) => R1] : never; // 将元组转换为联合类型 type IntersectionToUnion<T> = Overloads<T>[number];
测试示例(重载函数场景)
// 定义一个重载函数类型 type OverloadedFunc = ((a: number) => string) & ((a: string) => number); // 转换为联合类型 type FuncUnion = IntersectionToUnion<OverloadedFunc>; // 结果:((a: number) => string) | ((a: string) => number) // 验证转换正确性 type Equals<O1, O2> = (<T>(arg: T extends O1 ? T : T) => void) extends (<T>(arg: T extends O2 ? T : T) => void) ? true : false; type ExceptTrue<T extends true> = T; type Test = ExceptTrue<Equals<FuncUnion, ((a: number) => string) | ((a: string) => number)>>; // Test 类型为 true,说明转换正确
二、普通对象交叉类型的说明
你提供的测试案例里,{ a: 1 } & { b: 2 } 本质等价于 { a: 1, b: 2 }——对象交叉类型的语义是合并所有属性。如果硬要把它转成 { a: 1 } | { b: 2 },相当于改变了类型的核心语义(从同时拥有a、b属性变成只拥有其中一个),这种转换不符合TS的类型等价规则,没有内置支持,也不建议这么做。
总结
针对重载函数的交叉类型,用上面的类型工具就能转成函数联合类型,方便你遍历单个重载实现;而普通对象交叉类型的场景,不建议做这种语义不符的转换。
内容的提问来源于stack exchange,提问作者高厉害
相关产品推荐
相关产品推荐

