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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 08:03:29