为何Equal类型工具中Point构造函数类型与PointConstructor接口不相等?
为什么自定义Equal类型判断typeof Point和PointConstructor不相等,但双向extends都为true?
先看复现代码:
type Equal<A, B> = (<T>() => T extends A ? 1 : 0) extends <T>() => T extends B ? 1 : 0 ? true : false class Point { x: number y: number constructor(x: number, y: number) { this.x = x this.y = y } } interface PointConstructor { new (x: number, y: number): Point } type bo = Equal<typeof Point, PointConstructor> // type bo = false type bo1 = typeof Point extends PointConstructor ? true : false // type bo1 = true type bo2 = PointConstructor extends typeof Point ? true : false // type bo2 = true
核心原因拆解
两个类型的本质差异
typeof Point是TypeScript自动推导的类构造函数类型,它除了包含new(x: number, y: number): Point的构造签名,还隐含了类的静态成员(比如默认存在的prototype属性);而PointConstructor是你手动定义的接口,只包含构造签名这一个成员。双向extends的兼容性逻辑
TypeScript的结构类型系统中,extends做的是成员兼容性检查:
typeof Point extends PointConstructor为true:因为typeof Point包含了PointConstructor要求的所有必要成员(构造签名),满足子类型兼容父类型的规则。PointConstructor extends typeof Point为true:当接口extends类构造函数类型时,TypeScript会忽略类构造函数类型中的静态成员,只校验构造签名的一致性,两者构造签名完全匹配,因此判定兼容。
- Equal类型的严格相等逻辑
自定义的Equal类型利用了函数类型的逆变特性实现严格相等判断:它把A和B放到泛型函数返回值的条件类型中,通过比较两个函数类型是否完全兼容,来判断原类型是否严格相等。
由于typeof Point比PointConstructor多了静态成员,两者作为泛型约束时的范围并不完全一致,导致对应的函数类型不兼容,最终Equal返回false。
简单总结:双向extends是宽松的结构兼容性检查,只要必要成员匹配就通过;而Equal是严格的全量类型相等检查,要求两个类型的所有细节(包括隐含成员)完全一致才会返回true。
内容的提问来源于stack exchange,提问作者mengjie guo
相关产品推荐
相关产品推荐

