TypeScript Expect类型未识别嵌套可选属性差异及深度校验问题
TypeScript类型相等校验问题解答
1. 原Expect类型未报错的核心原因
- 你当前实现的
Expect根本不是类型相等校验工具,它仅做了单向子类型检查:泛型约束T extends E只验证T是否可以赋值给E(即T是E的子类型),完全没有校验反向的E是否可以赋值给T,本身就不满足相等判断的基本要求。 - TypeScript 采用结构化类型系统,对象类型的子类型判断规则是:如果源类型的每个属性都能赋值给目标类型对应属性,就判定子类型成立。你的测试case中:
- 两个类型的
prop1定义完全一致; - 两个类型的
prop2都是可选属性,TypeA 的prop2类型是{str: string},TypeB 的prop2类型是{str?: string},前者是后者的子类型(必填的str: string完全符合可选str?: string的赋值要求)。
- 两个类型的
- 因此
TypeA extends TypeB成立,原Expect直接返回true,完全没有检测到「TypeB 的prop2.str是可选、无法赋值给TypeA的必填str: string」这个差异,自然不会报错。
2. 严格深度相等类型的实现方式
真正的类型严格相等需要满足两个核心要求:一是双向子类型兼容,二是能识别可选/只读修饰符、any类型、联合/交叉类型等边缘场景的差异,单纯手写双向extends判断无法覆盖所有边界case(比如会错误判定any和任意类型相等)。
社区通用的稳定严格深度相等实现利用了TypeScript编译器对泛型函数签名的同一性判断逻辑,代码如下:
/** * 严格判断两个类型是否完全相等,支持深度嵌套、修饰符、any等边界场景 */ type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false; /** * 改造后的Expect工具类型:仅当传入类型为true时通过校验,否则抛出类型错误 */ export type Expect<T extends true> = T;
使用时直接用Equals包裹两个待比较类型即可,你的测试case会正确触发类型错误:
type TypeA = { prop1: { str: string; }; prop2?: { str: string; }; } type TypeB = { prop1: { str: string; }; prop2?: { str?: string; } } // 此处会正确抛出类型错误:Equals<TypeA, TypeB>返回false,不满足extends true的约束 type _Check = Expect<Equals<TypeA, TypeB>>; // 相等场景正常通过校验 type _ValidCheck = Expect<Equals<TypeA, TypeA>>;
补充说明:这个
Equals实现可以正确识别可选属性、只读属性、any/unknown/never等特殊类型、联合类型的差异,覆盖绝大多数静态类型测试场景。如果需要处理函数参数、类实例等更复杂的场景,可以基于这个基础逻辑做针对性扩展。
内容的提问来源于stack exchange,提问作者SILENT
相关产品推荐
相关产品推荐

