← 中文资源

简体中文版本

编译期类型断言工具

用 Equal、Expect、IsAny 与轻量运行时助手在 tsc 阶段断言类型相等,提前捕获类型回归。

阅读英文原文

功能说明

该示例提供一组类型级断言工具,让类型行为也进入测试范围。Equal 判断两个类型是否完全相同,Expect 要求条件必须为 true,IsAny 检测 any,TypeAssertions 把多条断言集中在一起。只要有一条不满足,tsc 就会报错,从而在 CI 中阻止类型回归。它还提供两个零成本的运行时助手,方便在测试代码中表达期望。

关键代码

Equal 使用经典的函数参数逆变技巧,用两个只在条件类型上不同的泛型函数互相赋值,从而区分 any、unknown、联合类型顺序与可选修饰符。Expect 的泛型约束为 true,传入 false 会直接编译失败。IsAny 利用 0 extends 1 与 any 的交叉结果为 any 的特性。expectType 原样返回参数以保留字面量类型,expectAssignable 只检查可赋值性。

使用注意

类型断言只有在 tsc 或 astro check 真正执行时才有意义,纯运行时测试不会触发。Equal 对 readonly 修饰符敏感,写断言时要确认期望的精确形状。expectType 不是严格相等断言,它只约束参数可赋值给 Expected,需要精确比较时仍应使用 Equal。不要在生产代码中保留大量测试类型,可放入单独的测试文件并由 tsconfig 包含。

验证方式

在 TypeAssertions 中放置 string 与 string、unknown 的 IsAny 为 false、any 的 IsAny 为 true、联合顺序无关等断言,运行 tsc 应通过。故意把一条改成 false,确认 tsc 报类型不满足约束。运行示例确认 expectType 返回原对象、expectAssignable 接受联合类型中的两种值。

代码示例

export type Equal<Left, Right> =
  (<Value>() => Value extends Left ? 1 : 2) extends <Value>() => Value extends Right ? 1 : 2
    ? true
    : false;

export type Expect<Condition extends true> = Condition;

export type IsAny<Value> = 0 extends 1 & Value ? true : false;

export function expectType<Expected>(value: Expected): Expected {
  return value;
}

export function expectAssignable<Expected>(value: Expected): void {
  void value;
}

export type TypeAssertions = [
  Expect<Equal<string, string>>,
  Expect<Equal<IsAny<unknown>, false>>,
  Expect<Equal<IsAny<any>, true>>,
  Expect<Equal<"a" | "b", "b" | "a">>,
  Expect<Equal<{ id: number }, { id: number }>>,
];

const user = expectType<{ id: number }>({ id: 1 });
console.log(user.id);
expectAssignable<string | number>("ok");
expectAssignable<string | number>(42);