TypeScript中Equals工具类型的工作原理及泛型T的作用是什么?
TypeScript Equals 工具类型实现原理详解
核心原理
这个Equals类型是利用TypeScript内部对未解析泛型条件类型的全等校验规则实现的,完美避开了普通双extends判断的边界问题(比如any、联合类型、属性修饰符误判的情况)。
逐段拆解实现
type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;
1. 占位泛型T的作用
这里的T不需要传入任何实际类型,只是一个用来构造「延迟解析条件类型」的占位参数,你可以把它理解为触发TS内部校验逻辑的工具人,没有实际的业务含义。
当泛型参数T没有被指定具体值的时候,T extends X ? 1 : 2不会被立刻计算结果,TS会把它当成一个完整的类型表达式储存。
2. 函数类型的可赋值性判断规则
TS在判断两个函数类型是否存在子类型关系时,会依次校验参数和返回值的兼容性:
- 两个函数都是无参泛型函数,参数完全兼容
- 接下来会校验返回值的两个条件类型是否等价
这里TS有一个专门的内部规则:只有当两个未解析的泛型条件类型的判断条件完全相等时,才会判定这两个条件类型等价。
也就是说:
只有X和Y完全相等(包括类型修饰符、联合类型顺序无关、排除any的兼容性污染),T extends X ? 1 : 2才会和T extends Y ? 1 : 2等价,对应的两个函数类型才会满足extends的子类型关系,最终返回true,否则返回false。
对比普通双extends判断的优势
普通的全等实现type Equals<X,Y> = X extends Y ? Y extends X ? true : false : false有大量边界问题,比如:
Equals<any, number>会误判为true,因为any可以赋值给任何类型,任何类型也可以赋值给anyEquals<{a: number}, {readonly a: number}>会误判为true,普通extends判断不会校验readonly修饰符Equals<never, number>会误判为true,因为never是所有类型的子类型
而本实现所有这些边界情况都可以正确判断。
内容的提问来源于stack exchange,提问作者jayatubi
相关产品推荐
相关产品推荐

