never 类型与不可能状态
使用 never 对不可达代码和不可能的值进行建模。
never 类型与不可能状态 是 CoddyKit 上的免费 TypeScript Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 TypeScript Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 TypeScript Academy 课程共包含 4 节课。
never 类型
never 是空类型,表示永远不可能出现的值。没有任何值可以赋给 never(never 自身除外)。它用于标记本应不可能发生的情况。
// You cannot create a value of type never
function crash(): never {
throw new Error('boom');
}
try { crash(); } catch (e) { console.log('caught'); }永不返回的函数
始终执行 throw 的函数不会正常返回,因此其返回类型是 never。这会告诉调用者(以及编译器)执行会在此处停止。
function fail(message: string): never {
throw new Error(message);
}
try { fail('invalid'); } catch (e) { console.log('handled'); }无限循环返回 never
包含无限循环的函数同样永远不会返回,因此其类型也是 never。编译器能够识别出控制流无法越过该函数继续执行。
function listen(): never {
while (true) {
// forever
break; // (break added so the demo terminates)
}
throw new Error('stopped');
}
console.log('listen has return type never');never 与 void
不要将 never 与 void 混淆。void 函数会返回,只是不会产生有用的值。never 函数则完全不会返回,而是抛出异常或永远循环。
function logIt(): void {
console.log('done'); // returns normally
}
function abort(): never {
throw new Error('stop'); // never returns
}
logIt();
try { abort(); } catch (e) { console.log('ok'); }在穷尽性检查中使用 never
never 最实用的用途是穷尽性检查。在 switch 的默认分支中,将变量赋给 never。如果所有情况都已处理,该变量本身已经是 never,代码就能通过编译。
type Shape = 'circle' | 'square';
function area(s: Shape): string {
switch (s) {
case 'circle': return 'pi r^2';
case 'square': return 'a^2';
default:
const _check: never = s; // ok: all handled
return _check;
}
}
console.log(area('square'));捕获遗漏的情况
如果有人新增了联合成员却忘记添加对应分支,剩余值就不再是 never,因此赋值无法通过编译。never 检查会将一个无声的遗漏变成明确的错误。
type Shape = 'circle' | 'square' | 'triangle';
// If 'triangle' case is missing, assigning s to never
// would error: 'triangle' is not assignable to never.
console.log('Add a case for every member');在不可能的联合分支中使用 never
当类型缩小排除了所有可能性后,剩余类型就是 never。编译器知道该分支无法到达,这可以帮助发现逻辑错误。
function check(x: string | number): void {
if (typeof x === 'string') {
console.log('string');
} else if (typeof x === 'number') {
console.log('number');
} else {
// x is never here
console.log('unreachable');
}
}
check('hi');never 作为底部类型
never 是底部类型:它可以赋给所有其他类型,因为不可能存在的值自然与任何类型都兼容。这就是为什么 throw 可以出现在任何表达式位置。
function getOrThrow(v: string | null): string {
return v ?? fail();
}
function fail(): never {
throw new Error('missing');
}
console.log(getOrThrow('value'));将联合类型过滤为 never
在条件类型和映射类型中,never 起到“移除该项”的作用。与 never 进行联合不会改变任何内容:T | never 就是 T。因此,它自然适合用于过滤。
type Keep<T> = T extends string ? T : never;
type R = Keep<'a' | 1 | 'b'>; // 'a' | 'b'
const x: R = 'a';
console.log(x);建模不可能的状态
在对象结构中使用 never,可以让非法组合无法表示。在这里,“加载中”状态不能同时携带数据,因为类型禁止了这种组合。
type State =
| { status: 'loading'; data?: never }
| { status: 'ready'; data: number };
const s: State = { status: 'ready', data: 7 };
console.log(s);never 提升重构安全性
由于 never 穷尽性检查会在遗漏分支时失败,因此它能让重构更安全:扩展联合类型后,编译器会指出每个需要更新的位置。
type Cmd = 'start' | 'stop';
function run(c: Cmd): string {
if (c === 'start') return 'starting';
if (c === 'stop') return 'stopping';
const _x: never = c;
return _x;
}
console.log(run('start'));快速检查
测试您对 never 类型的理解。
回顾:永不类型
您已学会,never:
- 是空类型——没有任何值可以属于这种类型。
- 是会抛出异常或无限循环的函数的返回类型。
- 为 switch 默认分支中的穷尽性检查提供支持。
- 会出现在不可能的缩窄分支中,并在类型逻辑中过滤联合类型。
接下来,我们将了解void及其区别。
function assertNever(x: never): never {
throw new Error('Unexpected: ' + String(x));
}
console.log('assertNever guards exhaustiveness');常见问题解答
「never 类型与不可能状态」课时是免费的吗?
是的 — 「never 类型与不可能状态」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 TypeScript Academy 课程的其余内容,请升级到 CoddyKit PRO。 TypeScript Academy 课程共包含 4 节课。
「never 类型与不可能状态」这节课中我会学到什么?
使用 never 对不可达代码和不可能的值进行建模。 你通过在浏览器中直接运行的动手代码来练习 TypeScript Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 TypeScript Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 TypeScript Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「never 类型与不可能状态」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 TypeScript Academy 课中编写并运行代码吗?
能。每节 TypeScript Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 理解 unknown 与 any
- never 类型与不可能状态
- 函数中的 void 类型
- 类型安全地处理 unknown