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 废弃标记与条件类型的分支裁剪。


参考文档

本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。

延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台