选 void 还是 never,关键看函数“是否可能正常结束”:能执行完返回 undefined 用 void;永远不返回(抛错/死循环)用 never。

选 void 还是 never,关键看函数“是否可能正常结束”。函数能执行完、返回 undefined(隐式或显式),就用 void;函数根本不会有“返回”这回事——要么抛错、要么死循环、要么永远卡住——那就必须用 never。
void:函数执行完毕,不返回有意义的值
void 表示函数有明确终点,只是不返回可使用的值。它不是“没类型”,而是“有意忽略返回值”,实际返回的是 undefined(TypeScript 会自动补上)。
- 日常日志、DOM 操作、状态更新等副作用函数都属于这一类
- 可以被后续代码安全调用,不影响控制流
- 允许显式写
return undefined,但不能返回其他值(如return 42会报错) - 类型上,
void变量只能赋undefined(null默认不允许,除非启用了strictNullChecks: false)
例子:
function log(msg: string): void {
console.log(msg); // ✅ 正常执行完
}
function updateUI(): void {
document.body.classList.add('loading');
return undefined; // ✅ 显式返回也合法
}
never:函数压根不会到达终点
never 表示函数的执行流“在此中断且永不恢复”——没有正常退出路径。编译器据此能推断出后续代码不可达,也能辅助类型收窄。
- 典型场景:抛出异常、无限循环、调用
process.exit()等终止进程的操作 - 在联合类型判断末尾出现
else分支时,TypeScript 自动推导为never,提示你漏处理了某种情况 - 可用于详尽性检查(exhaustiveness checking),比如
switch覆盖所有字面量联合类型后,default分支接收never来捕获遗漏
例子:
function fail(msg: string): never {
throw new Error(msg); // ✅ 永远不会执行到函数结尾
}
function loopForever(): never {
while (true) {} // ✅ 没有出口
}
// 类型收窄示例
function handleInput(x: string | number): string {
if (typeof x === 'string') return x.toUpperCase();
if (typeof x === 'number') return x.toString();
// x 此时类型是 never —— 编译器确认已穷尽所有可能
return x; // ❌ 类型错误,提醒你逻辑不完整
}
常见误用与判断技巧
容易混淆的点:
-
return;和return undefined;都是void,不是never -
async函数即使内部throw,返回类型仍是Promise<void></void>或Promise<t></t>,不是never(因为 Promise 本身会 resolve/reject,函数体仍会结束) - 不要为“可能抛错”的函数盲目标
never——只有当它 保证不返回 才适用。比如一个可能成功也可能失败的 API 调用,应返回Promise<t></t>,而非never
快速判断口诀:
✅ 调用后还能继续写代码?→ void
❌ 调用后下面的语句绝对执行不到?→ never
配合类型守卫和联合类型更实用
never 在类型推导中真正发力的地方,是和其他类型配合使用:
- 当
if/switch已覆盖全部可能,剩余分支变量类型自动变为never,帮你发现遗漏 - 定义
assertNever(x: never)辅助函数,让未处理分支直接报错,提升类型安全性 -
void则更多用于接口契约声明,比如事件处理器、钩子函数,强调“只做事情,不关心结果”
例如:
type Status = 'idle' | 'loading' | 'success' | 'error';
function getStatusMessage(s: Status): string {
switch (s) {
case 'idle': return 'Ready';
case 'loading': return 'Working...';
case 'success': return 'Done!';
case 'error': return 'Oops!';
default:
// s 在此处必为 never,若新增 status 但没加 case,这里会报错
const _exhaustiveCheck: never = s;
throw new Error(`Unhandled status: ${s}`);
}
}











