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

TypeScript中如何理解逆变下的`F<T|U> = F<T> & F<U>`?

TypeScript逆变类型等价性的困惑

StackOverflow的《typescript intersection types of function》文章提到:

逆变会将事物转为对偶形式;若F<T>对T逆变,则F<T | U>等价于F<T> & F<U>,F<T & U>等价于F<T> | F<U>。

我对这个等价性的证明方式存在困惑,以下是相关代码示例:

type Contra<T> = (arg: T) => any
type T1 = Contra<string> & Contra<number>
type T2 = Contra<string | number>
type T3 = Contra<string> | Contra<number>

declare let f1: T1;
declare let f2: T2;

f1(1); f1('1')
f2(1); f2('1')

f1 = f2;
f2 = f1; // 无法将f1赋值给f2

declare let f3: T3;
f3(1) // 正如预期是never,但如何直观理解?

一、如何理解F<T | U> ≡ F<T> & F<U>的等价性?

首先明确逆变的核心逻辑:函数的参数类型是逆变的——如果类型X是Y的子类型,那么接受Y的函数可以赋值给接受X的函数(能处理更宽泛类型的函数,必然能处理其子类型)。

回到示例:

  • Contra<string | number>是能接受string或number的函数,它的参数签名必须兼容两种类型的输入;
  • Contra<string> & Contra<number>是同时满足“接受string”和“接受number”的函数(交叉类型表示函数必须具备两种类型的所有特性)。

从语义上,这两种类型完全等价:能处理string | number的函数,必然能单独处理string或number;反过来,能同时处理string和number的函数,也必然能处理它们的联合类型。

代码中f2 = f1报错是TypeScript的类型检查细节:交叉函数类型会被视为重载函数,重载函数赋值给单一签名的函数时,TypeScript需要确认每个重载都能兼容目标签名的参数。f1的两个重载分别只接受string或number,无法直接兼容string | number的联合参数(因为传入其中一种类型时,无法确定匹配哪个重载)。但从类型集合的角度,两者确实是等价的——只是TypeScript的类型系统在表达上有这个限制。

二、为什么f3(1)会提示never?

f3的类型是Contra<string> | Contra<number>,也就是这个函数要么只能接受string,要么只能接受number。

当调用f3(1)时,TypeScript无法确定f3的具体类型:

  • 如果f3是Contra<string>,传入number会报错;
  • 如果f3是Contra<number>,传入number是合法的。

联合类型的调用需要满足所有分支都合法,因此只有当参数同时属于string和number时,调用才不会出错——但string和number的交集是never(不存在同时属于两种类型的值),所以f3的合法参数只能是never,也就是无法正常调用。

三、如何理解F<T & U> ≡ F<T> | F<U>的等价性?

用逆变逻辑推导:

  • T & U是同时属于T和U的窄类型(是T和U的子类型);
  • Contra<T & U>是接受T & U的函数;
  • Contra<T> | Contra<U>是要么接受T、要么接受U的函数。

根据逆变规则:

  • 接受T的函数可以赋值给接受T & U的函数(因为T & U是T的子类型,能处理T的函数必然能处理其子类型);
  • 同理,接受U的函数也可以赋值给接受T & U的函数。

反过来,任何能接受T & U的函数,本质上都属于“能接受T”或“能接受U”的函数集合——因为T & U同时是T和U的子类型,能处理它的函数必然兼容其中至少一种父类型的输入。因此Contra<T & U>和Contra<T> | Contra<U>是等价的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 18:45:42