如何编写针对TypeScript编译错误触发逻辑的单元测试
现成的类型测试成熟方案
针对你需要校验「自定义泛型约束是否按预期触发TS编译错误」的需求,完全不需要自行封装tsc调用逻辑,目前生态里有三类经过验证的成熟工具可以直接用:
1. 专为TS库设计的类型测试工具tsd
这是目前TS开源工具库做类型回归测试的事实标准,完全匹配你的场景:
- 独立维护测试用例文件,配置单独的路径规则,完全不会干扰正常的项目构建、发布流程
- 内置断言能力,可以同时校验两类场景:
- 正确入参的场景:类型是否完全匹配、没有额外的类型放宽
- 错误入参的场景:是否真的触发了预期的类型报错
- 对应你的示例场景的写法参考:
import { expectError, expectType } from 'tsd'; import { MyClass, someFunction } from './你的工具库入口'; const myClass = new MyClass(); // 正确场景:传入类上的方法名,应该完全通过类型校验 expectType<ReturnType<typeof someFunction>>(someFunction(myClass, 'method')); // 错误场景:传入非函数的数字属性,必须触发类型报错——如果这行代码没报错,tsd会直接判定测试失败 expectError(someFunction(myClass, 'property')); - 它内置了和TS编译器完全对齐的错误判断逻辑,不需要你处理tsconfig继承、路径解析这类边角问题,只需要在配置里指定你项目的tsconfig路径,就能复用你库本身的编译规则做校验。
2. 零依赖的原生TS指令方案
如果不想引入额外的第三方工具,可以直接用TS内置的@ts-expect-error指令实现兜底校验:
- TS本身的规则是:
@ts-expect-error注释的作用是“标记下一行代码必然会触发类型错误”,如果下一行代码没有触发任何类型问题,TS编译器会主动抛出「未使用的@ts-expect-error」的编译错误 - 对应你的示例场景的写法:
const myClass = new MyClass(); // @ts-expect-error 传入非函数属性应该触发类型约束错误 someFunction(myClass, "property"); - 落地的时候只需要给这些测试用例单独配一个不参与发布流程的tsconfig,加一个执行
tsc --noEmit的npm脚本即可:如果后续迭代不小心把泛型约束改松了,导致传入"property"不再触发报错,tsc就会抛出未使用指令的错误,直接阻断流程。 - 这个方案的局限性是只能校验“必须报错的场景有没有报错”,没法灵活校验正确入参的返回值、泛型推断结果是否符合预期,适合简单的规则兜底场景。
3. 适配现有测试框架的轻量类型断言库expect-type
如果你已经在项目里用vitest、jest这类运行时测试框架,不想单独维护一套类型测试目录,可以直接用这个纯类型层面的断言库:
- 不需要跑运行时代码,所有的校验都是在TS编译阶段完成的,可以直接和现有的测试用例写在一起
- 支持非常细粒度的类型校验,比如泛型推断结果、参数类型联合的成员、函数返回值类型的严格相等校验
- 适合对类型规则精度要求很高的场景,比如复杂工具库的泛型逻辑迭代。
选型参考
- 如果你是维护对外发布的工具库,核心诉求是防止类型约束被意外破坏,优先选
tsd,维护成本最低,校验覆盖最完整 - 如果只是需要简单兜底类型规则不被改松,不想加额外依赖,直接用原生
@ts-expect-error配独立tsconfig的方案就足够 - 如果已经有成熟的测试框架,希望把类型校验和业务测试合并维护,选
expect-type即可
内容的提问来源于stack exchange,提问作者MarTic
相关产品推荐
相关产品推荐

