为何类型分解时TypeScript联合类型的分发会"失效"?
问题核心:条件类型的分布式特性与类型推断上下文
要理解这种差异,核心在于TypeScript的两个关键类型机制:
1. 分布式条件类型的触发条件
只有当泛型参数直接出现在条件类型的extends左侧时,才会触发分布式条件类型。即当泛型T是联合类型时,T extends U ? X : Y会被拆解为(T1 extends U ? X : Y) | (T2 extends U ? X : Y) | ...,对联合类型的每个分支逐一计算后合并结果。
在你拆分的版本中:
type UnionOfFunctions<T> = T extends any ? (arg: T) => void : never; // 此处触发分布式,生成函数联合类型 type UnionOfFunctionsToIntersection<T> = T extends (arg: infer I) => void ? I : never; // 此处的T是已计算完成的联合类型
当调用UnionOfFunctionsToIntersection<UnionOfFunctions<T>>时,传入的T是一个已经生成的具体联合类型(比如(arg:A)=>void | (arg:B)=>void)。此时UnionOfFunctionsToIntersection的条件类型中,T extends ...的T不是原始泛型参数,而是一个固定的联合类型,因此不会触发分布式拆分。TypeScript会对联合类型的每个分支单独执行推断,最终将结果合并为联合类型(A | B),而非交叉类型。
2. 函数联合类型的参数逆变推断
当你把整个函数联合类型直接放在extends左侧,去匹配单个函数类型时(比如(F1 | F2) extends (arg: infer I) => void),TypeScript会利用函数参数的逆变特性:要让函数联合类型能赋值给单个函数类型,单个函数的参数必须能被联合类型中所有函数的参数兼容,也就是参数类型需要是所有分支参数的交叉类型(A & B)。
这就是原版本和调整后版本生效的原因:
- 原版本:
(T extends any ? (a: T) => void : never)生成函数联合后,直接在同一条件类型的extends右侧做推断,属于对整个联合类型的整体匹配,触发逆变推断出交叉类型。 - 调整后的版本:
UnionOfFunctions<T>生成函数联合后,直接放在extends左侧进行整体匹配,同样触发逆变推断逻辑。
实例验证
假设T = A | B:
- 拆分版本:
UnionOfFunctions<T>得到(arg:A)=>void | (arg:B)=>void,传入UnionOfFunctionsToIntersection后,条件类型对两个分支分别推断,最终返回A | B。 - 原版本/调整版本:函数联合整体匹配
(arg: infer I)=>void,逆变规则要求I必须兼容A和B,因此推断出A & B。
内容的提问来源于stack exchange,提问作者svidgen
相关产品推荐
相关产品推荐

