TypeScript泛型箭头函数结合extends的类型定义工作原理
MyEqual 类型工作原理解析
这是TypeScript类型编程中实现严格类型相等判断的经典实现,你提到的infer并没有在这段代码里出现,整个逻辑完全围绕extends关键字的两类不同运行规则展开。
两层extends的不同逻辑
代码中一共出现两处extends,作用完全不同:
- 内层的
T extends X ? 1 : 2、T extends Y ? 1 : 2属于普通条件类型:逻辑很直白,当类型T可赋值给extends右侧的类型时,返回字面量类型1,否则返回2。 - 外层的
(<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2)是泛型函数类型的兼容性校验,这才是实现相等判断的核心。
泛型函数校验的特殊规则
TS在判断两个带泛型的无参函数类型是否满足extends(即是否可以互相赋值)时,不会直接对比泛型声明,而是会在类型系统内部生成一个全局唯一、无任何额外约束的虚拟类型,把这个虚拟类型代入两边的泛型参数T,再对比替换后两个函数的返回值是否完全一致:
- 如果虚拟类型代入后,两边返回值完全相同,就判定两个泛型函数类型兼容,整个条件类型返回
true - 如果返回值不同,就判定不兼容,返回
false
为什么能做到严格相等
普通的双向extends判断(即先判断X extends Y再判断Y extends X)只能校验两个类型是否可互相赋值,会把any和任意类型、带可选属性的父类型和子类型误判为相等,但这个实现不会:
- 当
X和Y完全是同一个类型时,不管代入的T是什么类型,T extends X和T extends Y的判断结果永远一致,两边函数的返回值永远相同,因此函数类型兼容,返回true - 只要
X和Y存在哪怕一点差异,TS生成的虚拟类型就会命中这个差异:要么T extends X成立但T extends Y不成立,要么反过来,导致两边返回值一个是1一个是2,函数类型不兼容,返回false
几个常见场景的运行结果:
MyEqual<boolean, boolean>→trueMyEqual<boolean, true | false>→true(二者在TS中是同一个类型)MyEqual<any, string>→false(普通双向extends会误判为true)MyEqual<{id: number}, {id: number, name?: string}>→false(普通双向extends会误判为true)
注:这个实现依赖TS内部的类型检查逻辑,属于官方文档没有明确说明的行为,存在大版本更新后失效的可能,但从TS 2.x到当前5.x的所有正式版本中都可以正常工作。
内容的提问来源于stack exchange,提问作者Daniel Rodríguez Meza
相关产品推荐
相关产品推荐

