如何将TypeScript类型元组转换为类型交集?
如何将类型元组转换为所有类型的交集?
现有一个用于将元组类型转为所有元素类型交集的TypeScript类型工具,但在处理包含any的元组时,结果不符合预期:
type TupleToIntersection< Rest extends any[], T = Rest extends [any, ...any[]] ? Rest['0'] : never, > = Rest extends [infer H, ...infer S] ? TupleToIntersection<S, H & T> : T type TTest1 = TupleToIntersection<[string, any, number]> // 实际结果:any,预期结果:never! type Test1 = string & any & number // 结果为never(符合预期) type Test2 = (string & any) & number // 结果为any(当前工具的执行逻辑)
问题根源
问题出在交集运算的结合顺序:当前工具采用从左到右的累积合并方式,先计算string & any得到any,再和number交集仍为any;但直接书写无括号的多类型交集时,TypeScript会按右结合逻辑处理,先计算any & number得到never,再和string交集最终为never。
解决方案
方案1:调整递归合并顺序(简单直接)
修改递归逻辑,先处理元组的剩余元素,再将当前元素与剩余元素的交集结果合并(即右结合顺序):
type TupleToIntersection<Rest extends any[]> = Rest extends [infer H, ...infer S] ? H & TupleToIntersection<S> : unknown;
测试验证:
type TTest1 = TupleToIntersection<[string, any, number]> // never(符合预期) type TTest2 = TupleToIntersection<[{a: 1}, {b: 2}, {c: 3}]> // {a: 1} & {b: 2} & {c: 3}
方案2:利用函数参数逆变特性(社区标准实现)
TypeScript中函数参数类型是逆变的,基于这一特性可以实现更通用的元组转交集逻辑,这也是社区广泛使用的标准写法:
type TupleToIntersection<T extends any[]> = (T extends any ? (x: T) => void : never) extends (x: infer U) => void ? U : never;
测试验证:
type TTest1 = TupleToIntersection<[string, any, number]> // never(符合预期) type TTest3 = TupleToIntersection<[boolean, string[], {id: number}]> // boolean & string[] & {id: number}
内容的提问来源于stack exchange,提问作者TrevTheDev
相关产品推荐
相关产品推荐

