前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库TypeScript never switch 穷尽检查
TyTypeScript类型系统基础

TypeScript 如何用 never 检查 switch 是否处理了全部联合分支?

穷尽检查的价值出现在类型演进时:新增一种状态,应提醒所有需要处理它的位置。

前端进阶之旅 · 一题精讲更新于 2026.09.06
TypeScript#类型系统基础#类型系统#实时通信
先看核心答案读代码示例
理解线索

让新状态找到遗漏处理点

  1. 有限联合明确列出当前允许的状态及关联数据
  2. 逐支处理根据标签分别执行对应分支的行为
  3. 剩余验证确认 default 已不存在未处理的合法成员

never 是没有正常可用值的类型,不能与表示不关心返回值的 void 混为一谈。

核心回答

先记住这个答案

对有限联合逐个处理成员后,剩余分支的值应被收窄为 never,表示在当前类型契约下已经没有合法候选。可以在 switch 的 default 中调用只接收 never 的辅助函数;新增联合成员而漏写 case 时,剩余值不再是 never,编译器就会报错。辅助函数通常直接抛错并返回 never,兼顾运行时异常输入。不要把 default 随意返回空字符串当作穷尽检查,那会让新增状态悄悄进入兜底路径。

  • 处理完有限联合后,剩余候选应为 never
  • assertNever 参数负责检查遗漏成员
  • 运行时抛错用于暴露违反静态契约的输入

default 中为何需要接收 never

普通 default 可以接收任何未匹配状态,直接返回默认文案就会掩盖遗漏。只接收 never 的函数则要求调用位置已经排除了所有合法候选。新增一种状态后,编译器会把它保留在 default 中,从而拒绝这次调用并指出缺少处理。

示例用成功和失败两个成员构造结果类型,每个 case 都返回文案。最后的函数不会正常返回,既向类型系统描述不可达,也在输入违反契约时抛出错误。应把完整联合值传给检查函数,便于错误诊断保留未处理成员的结构。

用不可达分支检查状态演进TypeScript
type Result =
  | { kind: 'success'; count: number }
  | { kind: 'failure'; reason: string };
function assertNever(value: never): never {
  throw new Error('Unhandled result');
}
function describe(result: Result): string {
  switch (result.kind) {
    case 'success': return 'count=' + result.count;
    case 'failure': return result.reason;
    default: return assertNever(result);
  }
}

当前两个合法成员都有返回路径,default 参数可以归约为 never。若给 Result 增加 pending 成员而不补 case,assertNever(result) 应产生编译错误,提示状态处理需要同步更新。

return 和可达性会影响剩余类型

分支只有结束当前路径或形成明确互斥控制流,后续位置才会排除已经处理的候选。写了 case 却继续穿透到后续语句,或把标签转成宽字符串再判断,都可能让编译器无法证明剩余值为空。应查看报错位置实际推断出的类型。

never 也可用于返回类型,例如函数必定抛错或永不正常结束。void 则常用于不关心返回结果的调用契约,并不代表函数无法结束。穷尽辅助函数需要表达不存在正常返回路径,不能靠随意返回 undefined 来伪装这一点。

静态穷尽与未知输入怎样配合

有限联合来自可信内部状态时,编译检查能帮助维护所有处理点;来自网络的字符串则可能不在联合里。不能仅靠 as Result 把外部对象送进分支,再宣称所有运行时输入都已经覆盖。应先解析外部数据,之后再执行内部穷尽处理。

测试可以临时为类型添加一个新成员,确认关键处理函数出现预期诊断;同时以运行时错误输入验证兜底确实暴露异常。这个检查不是要求每个 switch 都抛错,开放协议可能需要明确的 unknown 状态,但它也应作为真实成员参与设计。

回答前,多想一步

容易答错的地方

写了 default 就已经覆盖所有状态
default 只是兜底路径,直接返回成功或空值会隐藏新增成员;穷尽检查需要让剩余类型无法赋给 never 时产生明确编译错误。
用 as never 可以修复穷尽检查报错
这会强行告诉编译器分支不可达,恰好移除了发现遗漏的机制;应检查新增成员或控制流,而不是断言消除证据。
试着用自己的话回答

面试官还会怎么问?

辅助函数为什么还要真的抛出错误?

类型检查会在生成代码后消失,错误断言或外部输入仍可能进入该路径;实际抛错能暴露契约被破坏,而不是返回一个伪造正常值。

开放字符串状态适合直接做穷尽检查吗?

无限字符串集合无法逐一列完,可以先映射到有限内部状态并保留明确未知分支,再对内部联合进行穷尽处理和监控。

只写显式返回类型能发现全部遗漏吗?

配合严格空值检查可能发现缺少返回路径,但不能替代对具体剩余成员的验证;never 检查更直接表达所有联合成员必须处理的意图。

从一道题,走向一组知识

把知识连起来

类型收窄

TypeScript 判别联合如何建模,为什么标签写成 string 后不能正确收窄?

先把状态与对应数据建模成可收窄的联合

类型系统基础

TypeScript interface extends 和交叉类型 & 组合对象时有什么区别?

对照 never 由冲突约束产生时的另一类问题

参考资料

  • TypeScript:Exhaustiveness Checking

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. default 中为何需要接收 never
  3. return 和可达性会影响剩余类型
  4. 静态穷尽与未知输入怎样配合
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑