You need to enable JavaScript to run this app. TypeScript 函数交叉类型推导疑问:h、i、e类型结果为何不符合预期
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript 函数交叉类型推导疑问:h、i、e类型结果为何不符合预期

TypeScript函数交叉类型推导逻辑解析

前置核心规则

  • 交叉类型本质:交叉类型表示值必须同时满足所有成员类型的约束,只要存在符合要求的值,交叉类型就不会退化为never。
  • 函数位置变种规则:函数类型中,参数位置属于逆变位置,返回值位置属于协变位置,类型推导的合并逻辑会随位置变化。
  • infer 推导实现规则:当前版本TypeScript中,从交叉类型的多个成员匹配推导时,逆变位置的infer候选值会按交叉成员顺序依次覆盖,而非自动合并。

对应疑问的具体解释

  1. 为什么type g = 1 & 2是never,但type h = ((x: 1) => 0) & ((x: 2) => 0)不是never?

    • 字面量类型1和2是不可兼容的基础原子类型,不存在任何值能同时既是1又是2,因此它们的交叉结果为never。
    • 但两个函数类型的交叉要求是:这个函数必须同时满足“能接收参数1并返回0”且“能接收参数2并返回0”。这类函数是真实存在的——比如参数类型为1 | 2的函数,完全可以同时满足两个约束,因此整个交叉类型是合法结构,不会退化为never。
  2. 为什么type i = ((x: 1 & 2) => 0)中的参数x不是never?

    • 这里存在认知偏差:1 & 2的计算结果本身就是never,因此x的标注类型就是never,不存在“不是never”的情况。
    • 实际疑惑的来源应该是“为什么这个函数类型没有退化为never”:函数类型的合法性仅取决于结构是否可存在,哪怕参数类型是never(代表这个函数永远无法被合法传入参数调用),这个函数结构本身也是合法的,不会因为参数是never就把整个函数类型变成never。
    • 补充:当never出现在函数参数位置时,由于不存在任何类型为never的值,这个参数的约束永远不会被触发,相当于函数可以接收任意类型的参数调用,但不会让函数类型本身变为never。
  3. 为什么type e = (((x: 1) => 0) & ((x: 2) => 0)) extends (x: infer L) => 0 ? L : never的结果是2,而非1或never?

    • 首先这个交叉的函数类型本身是合法结构,不是never,因此extends判定为成立,不会走到返回never的分支。
    • 匹配过程中,TS会把交叉的两个成员逐个和目标模式(x: infer L) => 0做比对:
      • 匹配第一个成员(x:1) => 0时,推导得到L的第一个候选值为1
      • 匹配第二个成员(x:2) => 0时,推导得到L的第二个候选值为2
    • 按照当前TS的infer实现逻辑,交叉类型多成员匹配时,逆变位置的infer候选值不会自动合并,而是按成员顺序依次覆盖,最后一个匹配成员的推导结果会覆盖之前的所有候选值,因此最终L会保留最后一个候选值2。
    • 注意:这个行为是TS的实现细节,不是理论类型系统的设计预期,后续版本可能会调整该推导逻辑。

内容的提问来源于stack exchange,提问作者xianshenglu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.01 07:54:00