You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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判断方向的逻辑差异:

  1. never的本质特性:never是TypeScript中表示"不存在的类型",它是所有类型的子类型,但没有任何类型(除自身外)是它的子类型。不过在条件类型的判断中,涉及never的extends规则有特殊处理。

  2. FilterOut2的[E] extends [F]判断逻辑:

    • 处理数组第一个元素"a"时,["a"] extends [never]不成立,因此保留"a",递归处理剩余数组[never]。
    • 处理第二个元素never时,[never] extends [never]结果为true,所以跳过该元素,递归处理空数组返回[]。最终拼接得到["a", ...[]],即["a"],结果符合预期。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 02:57:34