assertNever 穷尽检查

最后更新:2026-10-22

assertNever 穷尽检查

穷尽检查是保证"联合类型的每个成员都被处理"的编译期保险。核心是 assertNever 技巧:把 switch 的 default 分支参数声明为 never——如果漏了某个成员,那个成员还能传进来,参数就不是 never,编译器立刻报错。

分组收窄与断言
类型语法
严格模式不需要

ℹ️ 说明 编辑器将 TypeScript 转译为 JavaScript 后运行(不做类型检查);类型检查结果见示例 Output。

📝 语法

function assertNever(x: never): never {
  throw new Error("Unhandled: " + JSON.stringify(x));
}

function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle": return Math.PI * shape.radius ** 2;
    case "square": return shape.side ** 2;
    default:
      return assertNever(shape); // 漏分支时这里编译报错
  }
}

⚙️ 参数

x: nevernever 是所有类型的子类型且没有成员——只有当所有分支都处理完、剩余类型为空时,实参才满足 never

返回值:assertNever 返回 never(永不正常返回,运行时抛错);编译期的"返回值"是错误提示:Argument of type 'X' is not assignable to parameter of type 'never'。

▶ 示例

修改下面的代码,点击试一试查看转译运行结果:

输出:

3.14
9

(转译后运行输出:当前分支齐全,assertNever 走不到。若给 Shape 新增 kind: "triangle" 而不加分支,tsc 会在 default 行报 "Argument of type '{ kind: "triangle"; ... }' is not assignable to parameter of type 'never'")

💡 要点

ℹ️ 说明 原理:TS 对联合的 switch 会把已处理成员从类型中剔除。所有成员都处理后 shape 就是 never,能赋给 never 参数;漏一个成员就赋不进去,报错位置正是 default 行。
💡 提示 给联合新增成员是穷尽检查最大的价值时刻:不用全局搜索调用点,编译器会把所有漏处理的 switch 一次列出来。
⚠️ 注意 穷尽检查依赖可辨识联合:判别字段必须是字面量类型。switch 上判别字段但用 if-else 链、或判别字段类型是 string,编译器都无法判断穷尽性。
更多案例即将上线。

📚 相关教程

❓ 常见问题

Q 不用 assertNever,写全 switch 不行吗?
A TS 的 noImplicitReturns / strict 模式能发现"有的路径没有返回值",但无法发现"逻辑上少处理了一种情况"(比如某个分支 return 了默认值)。assertNever 把"漏处理"变成硬编译错误。
Q if-else 链也能做穷尽检查吗?
A 可以,在最后一个 else 里调用 assertNever(x) 即可,原理相同。但 switch 对可辨识联合的可读性和穷尽性分析都更友好,推荐 switch。
Q 运行时 assertNever 会被执行吗?
A 正确维护下不会——它只在"编译期已防住"的漏分支场景才会跑到。留着一个 throw 兜底是防御性编程:万一运行时数据与类型声明不符(如旧缓存数据),能尽早暴露而不是静默走错分支。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏