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

如何在TypeScript中实现两种类型的编译期相等验证?

TypeScript编译期类型断言(类似C语言static_assert)

我想实现类似C语言static_assert()的功能,仅针对编译期数据(比如不会被输出的类型信息),期望效果如下:

type TStrLit_0 = 'a' | 'b' | 'C' | 'd';
type TStrLit_1 = 'a' | 'b' | 'C' | 'd';
type TStrLit_2 = 'a' | 'b' | 'c' | 'd';
type TStrLit_3 = 'a' | 'b' | 'C';
type TStrLit_4 = 'a' | 'b' | 'C' | 'd' | 'e';

static_assert(TypesAreEqual<TStrLit_0, TStrLit_1>());
static_assert(!TypesAreEqual<TStrLit_0, TStrLit_2>());
static_assert(!TypesAreEqual<TStrLit_0, TStrLit_3>());
static_assert(!TypesAreEqual<TStrLit_0, TStrLit_4>());

type TObject_0 = { a: number, b: string };
type TObject_1 = { a: number, b: string };
type TObject_2 = { a: number, b: number };
type TObject_3 = { a: number, B: string };
type TObject_4 = { a: number };
type TObject_5 = { a: number, b: string, c: number };
type TObject_6 = { a: any, b: any };
static_assert(TypesAreEqual<TObject_0, TObject_1>());
static_assert(!TypesAreEqual<TObject_0, TObject_2>());
static_assert(!TypesAreEqual<TObject_0, TObject_3>());
static_assert(!TypesAreEqual<TObject_0, TObject_4>());
static_assert(!TypesAreEqual<TObject_0, TObject_5>());
static_assert(!TypesAreEqual<TObject_0, TObject_6>());

我需要基于TypeScript类型信息的通用编译期断言能力。编译器已经生成了类型信息但不会输出,运行时断言需要额外嵌入元数据,操作繁琐。编译期类型断言可以把假设的不变量嵌入代码,避免后续维护时无意破坏。

现在有两个问题:

  1. TypeScript是否已经内置了这类功能?
  2. 这个功能需要修改TypeScript核心,还是可以通过现有语法/功能实现?

解答

1. 是否已有内置功能?

目前TypeScript没有提供和C语言static_assert完全一致的原生语法,但从v4.9版本开始的satisfies运算符,以及类型系统的条件报错机制,可以间接实现类似效果,社区也有成熟的模拟方案。

2. 能否通过现有功能实现?

不需要修改TypeScript核心,完全可以通过现有类型系统特性实现。核心思路是利用条件类型触发编译报错:当断言条件不满足时,让TypeScript抛出类型错误。

具体实现

首先实现严格的类型相等判断工具:

// 严格判断两个类型是否完全相等
type TypesAreEqual<T, U> =
  (<G>() => G extends T ? 1 : 2) extends
  (<G>() => G extends U ? 1 : 2) ? true : false;

这个类型通过高阶类型推断,能精准识别类型的细节差异(比如字符串字面量大小写、对象属性名/类型、联合成员数量等)。

然后实现编译期断言工具:

// 编译期断言:条件为false时触发报错
type StaticAssert<Condition extends boolean> = Condition extends true ? never : "Assertion failed: expected condition to be true";

// 使用示例
type _CheckStrEqual = StaticAssert<TypesAreEqual<TStrLit_0, TStrLit_1>>; // 无报错
type _CheckStrNotEqual = StaticAssert<TypesAreEqual<TStrLit_0, TStrLit_2>>; // 编译报错

如果断言失败,StaticAssert会返回一个非never的类型,TypeScript会在类型检查时抛出错误(需确保开启noUnusedLocals配置,让未使用的类型别名也被校验)。

模拟函数调用风格

如果想贴近示例中的static_assert(...)写法,可以用泛型函数约束:

const static_assert = <T extends true>(_: T) => {};

// 使用示例
static_assert(TypesAreEqual<TStrLit_0, TStrLit_1> as true);
static_assert((!TypesAreEqual<TStrLit_0, TStrLit_2>) as true);

通过泛型约束T extends true,只有当传入的条件为true时才符合类型要求,否则会触发编译错误。

注意点

  • 建议开启strict模式,确保类型判断的准确性。
  • 对于极端复杂的递归类型或动态条件类型,TypesAreEqual可能存在局限性,但覆盖绝大多数常规类型场景足够。

内容的提问来源于stack exchange,提问作者Henry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 06:36:21