TypeScript条件类型为何匹配string/number正常却对boolean返回never?
TypeScript条件类型为何匹配string/number正常却对boolean返回never?
这个问题确实有点绕,我来给你拆解一下背后的原因。
核心问题出在TypeScript的分布式条件类型机制上,你的OutputFor<T>定义刚好触发了这个机制,导致boolean的处理逻辑跑偏了。
先理清楚关键的几个点:
- 你的
InputTypes是string | boolean | number,属于联合类型。 OutputFor<T>里的条件检查T extends InputTypes[]中,T是一个「裸类型参数」——也就是没有被元组、对象等包裹的类型参数,这会触发TypeScript的分布式条件类型规则。
按照TypeScript的规则,当条件类型的左侧是裸类型参数,右侧是联合类型时,会自动把条件类型拆分成联合类型每个成员的单独检查,最终结果是所有分支的联合。但这里有个容易踩坑的点:TypeScript会把InputTypes[](联合类型的数组)错误地解析成「T是否属于InputTypes的成员」,而不是「T是否是这个联合类型的数组」。
具体到你调用OutputFor<boolean>的场景:
- TypeScript会把
boolean extends InputTypes[]解析成boolean extends string | boolean | number,这个判断是true(因为boolean是InputTypes的成员),所以会走条件的then分支:OutputFor<T[number]>。 - 但
T是boolean类型,T[number]也就是boolean[number],这是个never类型——毕竟boolean不是数组,不存在number索引的成员。 - 接下来调用
OutputFor<never>,此时never extends InputTypes[]是false,走else分支:Extract<TypePairs, {input: never}>["output"],而Extract从TypePairs里找不到匹配{input: never}的成员,所以返回never,最终结果就是never。
那为什么string和number的情况能正常返回呢?
这是因为当调用OutputFor<string>时,虽然同样会触发分布式条件类型,走then分支OutputFor<string[number]>,但string[number]的结果还是string,递归调用OutputFor<string>时,TypeScript能识别出这种递归并终止,最终返回正确的string类型。number的情况也是同理。
要解决这个问题,你只需要阻止分布式条件类型的触发就行——把T包裹在元组里,让它不再是裸类型参数:
type OutputFor<T> = [T] extends InputTypes[] ? OutputFor<T[number]> : Extract<TypePairs, { input: T }>["output"];
这样TypeScript就会正确解析条件检查,boolean不属于数组类型,会走else分支,Extract就能正常返回boolean类型了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

