TypeScript中[F] extends [E]与[E] extends [F]为何表现不同?
问题:TypeScript条件类型判断顺序引发的过滤结果差异
我定义了两个仅条件判断顺序不同的TypeScript条件类型FilterOut与FilterOut2:
type FilterOut<T extends any[], F> = T extends [infer E, ...infer Rest] ? [F] extends [E] ? FilterOut<Rest, F> : [E, ...FilterOut<Rest, F>] : []; type FilterOut2<T extends any[], F> = T extends [infer E, ...infer Rest] ? [E] extends [F] ? FilterOut2<Rest, F> : [E, ...FilterOut2<Rest, F>] : []; type Test = FilterOut<["a", never], never>; // Output [] type Test2 = FilterOut2<["a", never], never>; // Output ["a"]
二者分别用[F] extends [E]和[E] extends [F]做判断,针对相同输入["a", never]、过滤类型为never的测试,输出结果完全不同。请问这两种判断方式为何会产生差异?
解答
核心原因在于**never类型的特殊行为**,以及两种extends判断方向的逻辑差异:
never的本质特性:never是TypeScript中表示"不存在的类型",它是所有类型的子类型,但没有任何类型(除自身外)是它的子类型。不过在条件类型的判断中,涉及never的extends规则有特殊处理。FilterOut2的[E] extends [F]判断逻辑:- 处理数组第一个元素
"a"时,["a"] extends [never]不成立,因此保留"a",递归处理剩余数组[never]。 - 处理第二个元素
never时,[never] extends [never]结果为true,所以跳过该元素,递归处理空数组返回[]。最终拼接得到["a", ...[]],即["a"],结果符合预期。
- 处理数组第一个元素
FilterOut的[F] extends [E]判断逻辑:- 处理第一个元素
"a"时,[never] extends ["a"]不成立,保留"a"并递归处理[never]。 - 关键差异出在处理
[never]的步骤:当E被推断为never时,[never] extends [never]这个判断并不会返回true,而是触发TypeScript的特殊规则——如果条件类型的某一侧是never且涉及泛型推断,整个条件表达式的结果会变成never。 - 这导致
FilterOut<[never], never>的结果不是预期的[],而是never。将前面的"a"与这个结果拼接时,["a", ...never]会被解析为never,而TypeScript最终会将never数组等价于空数组[],所以Test的结果就变成了[]。
- 处理第一个元素
简单来说:
[E] extends [F]判断never时结果明确为true,能正常执行过滤逻辑。[F] extends [E]判断never时,条件表达式会变成never,导致递归分支失效,最终整个数组被消解为空数组。
内容的提问来源于stack exchange,提问作者runlong
相关产品推荐
相关产品推荐

