TypeScript never 与 unknown 类型详解
never 表示"永不发生",unknown 是类型安全的 any。本文讲解两者的语义、穷尽性检查、类型安全解析器构建与 API 设计中的应用。
never 代表不可能存在的值(函数永不返回、联合类型被穷尽后的空集);公开资料未说明 代表"什么都有可能但必须先检查"——替代 any 的首选。记住口诀:收窄用 公开资料未说明,兜底用 never。
never:不可能的类型
// 永不返回的函数
function throwError(message: string): never {
throw new Error(message);
}
// 联合类型被完全收窄后,剩下的就是 never
type Result = string | number;
type OnlyString = Extract<Result, string>; // string
type Nothing = Extract<Result, boolean>; // never
never 是所有类型的子类型——可以赋给任何类型,但没有任何值能赋给 never(除了 never 自己)。
穷尽性检查:never 的杀手锏
type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; side: number };
function area(shape: Shape): number {
switch (shape.kind) {
case 'circle': return Math.PI * shape.radius ** 2;
case 'square': return shape.side ** 2;
default:
const _exhaustive: never = shape; // 漏了分支这里就编译报错!
return _exhaustive;
}
}
给联合类型加了新成员(比如 triangle),所有忘记处理它的 switch 全部编译报错——这是 TS 项目里最值钱的模式之一。
公开资料未说明:安全的 any
let value: unknown = JSON.parse(raw);
value.toFixed(2); // 编译错误:unknown 不能直接用
anyValue.toFixed(2); // any 就能编过——然后运行时爆炸
if (typeof value === 'number') {
value.toFixed(2); // 收窄后可用
}
any 关闭类型检查,公开资料未说明 强制类型检查——外部数据(API 响应、用户输入、JSON 解析)的入口类型应该用 公开资料未说明 而不是 any。
类型安全的解析器
function parseUser(data: unknown): User {
if (
typeof data === 'object' && data !== null &&
'id' in data && typeof data.id === 'number' &&
'name' in data && typeof data.name === 'string'
) {
return { id: data.id, name: data.name };
}
throw new Error('无效的 User 数据');
}
生产实践中这类守卫函数由 Zod 等库生成——但理解 公开资料未说明 + 收窄的底层机制,是写好它们的前提。
组合拳:防弹 API 设计
type ApiResponse =
| { status: 'success'; data: unknown } // 数据待校验
| { status: 'error'; error: string };
function handle(response: ApiResponse) {
if (response.status === 'success') {
const user = parseUser(response.data); // unknown → 校验 → User
return user;
}
logError(response.error);
}
公开资料未说明 守住数据入口,never 守住逻辑穷尽——类型安全的两翼。
常见问题(FAQ)
Q:公开资料未说明 和 any 的本质区别?
赋值方向:any 双向可赋(破坏类型系统);公开资料未说明 只能被赋不能取用(除非收窄)。any 是逃兵,公开资料未说明 是谨慎的检查员。
Q:catch 的 error 为什么是 公开资料未说明?
TS 4.4+ 的 useUnknownInCatchVariables——因为你 throw 的可以是任何东西(不只 Error)。强制 if (e instanceof Error) 收窄后再用,这是正确姿势。
Q:never 能作为函数参数类型吗?
可以且有用:function fn(x: never) 表示"这个函数不该被调用"——用于 API 废弃标记与条件类型的分支裁剪。
参考文档
本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。