← 返回题目列表

any、unknown 和 never 有什么区别?

高频 中等 第 4 / 32 题 更新于 2026/07/27
TypeScriptanyunknownnever

简化版

any 会关闭类型检查,既能赋给别人也能被别人赋值;unknown 表示未知类型,使用前必须收窄,更安全;never 表示永远不会出现的值,常用于不可能返回的函数和穷尽检查。

详细版

any

let a: any = 1;
a.foo.bar(); // 编译不报错

unknown

let u: unknown = 1;
// u.toFixed(); // 报错
if (typeof u === 'number') {
  u.toFixed();
}

never

function fail(msg: string): never {
  throw new Error(msg);
}

面试中要强调:能用 unknown 就别用 any,因为 unknown 逼你做类型收窄。

完整版教学

一、any 是类型系统的逃生门

any 的危险在于它会传染。一旦一个值是 any,后续访问属性、调用方法、赋值都绕过检查。

这在迁移老项目时有用,但在新代码中滥用会让 TypeScript 退化成 JavaScript。

二、unknown 是安全的未知

unknown 表示我现在不知道它是什么,但在使用前必须证明。

function parse(input: string): unknown {
  return JSON.parse(input);
}

解析 JSON 的结果天然是不可信的,用 unknown 比 any 更合理。调用方必须通过 typeofArray.isArray、自定义类型守卫等方式收窄。

三、never 表示不可能

never 常出现在两类地方:函数永远不返回,或者类型收窄后已经没有剩余可能。

type Shape = { kind: 'circle'; r: number } | { kind: 'square'; w: number };

function area(s: Shape) {
  switch (s.kind) {
    case 'circle': return Math.PI * s.r * s.r;
    case 'square': return s.w * s.w;
    default:
      const _exhaustive: never = s;
      return _exhaustive;
  }
}

如果以后新增形状,default 里的 never 检查会提醒你漏处理。

四、工程建议

外部输入用 unknown,内部逐步收窄;临时迁移不得不用 any 时,要限制范围,别让 any 穿透到核心类型。

never 则是写类型安全分支时的好工具。它能让“不可能路径”进入类型系统,在联合成员扩展后及时暴露遗漏。

五、面试追问与工程落地

高频追问是“unknown 能不能赋给其他类型”。unknown 可以接收任何值,但不能直接赋给具体类型,除非先收窄或断言。any 对绝大多数类型都可双向赋值并跳过检查,正是这种自由让它危险;但 never 等边界仍有特殊规则。可以说 unknown 是类型安全的顶部类型,never 是底部类型。

还会问 never 在业务代码里有什么用。除了抛错函数,最实用的是穷尽检查。当联合类型新增分支时,never 能让编译器提醒你 switch 没处理完整,这对状态机、消息类型、权限分支很有价值。

工程里外部输入建议统一从 unknown 开始,比如 JSON.parse、第三方 SDK、postMessage、localStorage。先校验再进入业务类型,避免 as User 把脏数据伪装成干净数据。

六、用可赋值关系理解三个类型的位置

把类型看成“可能值的集合”更容易理解:unknown 可以容纳任意输入,但读取能力最少;never 没有任何可能值,所以可以赋给其他类型;any 则是编译器提供的逃生机制,不遵守普通的安全集合关系。尤其要注意,在赋值兼容性中 any 也不能直接赋给 never

let top: unknown = 42
let text: string = 'ok'
let bottom: never = (() => { throw new Error('stop') })()
top = text       // 可以:任何值都能进入 unknown
text = bottom    // 可以:never 不会产生实际值
// text = top    // 报错:使用 unknown 前必须收窄
类型能否接收普通值能否直接访问成员典型用途
any能,但不检查渐进迁移、错误类型的临时隔离
unknown不能,需收窄接口响应、消息、异常等边界输入
never不能不存在可用值穷尽检查、永不返回的控制流

假设一个联合类型有 3 个状态,switch 已处理其中 3 个后,剩余分支会收窄为 never;以后新增第 4 个状态,赋值给 never 就会编译失败。这个错误把“新增状态后漏改消费者”从线上风险提前成编译期反馈。

记忆钩子:unknown 是“什么都能进、未经证明不能出”,never 是“根本没有值能进”,any 是“暂时绕开门禁”。

七、常见误区与追问

  • 误区:unknown 和 any 只是名字不同。 两者都能接收任意值,但 unknown 禁止未经收窄的成员访问和具体类型赋值,any 会跳过检查。
  • 误区:never 和 void 都表示函数没有返回值。 void 表示调用方忽略返回值,函数仍可正常结束;never 表示控制流无法正常到达终点。
  • 误区:any 可以赋给包括 never 在内的所有类型。 any 能绕过大量检查,但不能直接赋给 never
  • 追问:unknown 为什么叫顶部类型? 任意类型的值都能安全赋给 unknown,它覆盖所有可能输入,但使用能力必须通过收窄取回。
  • 追问:never 为什么能赋给 string? never 没有实际可能值,从空集合到任意类型都不会制造不安全的运行时值。
  • 追问:catch 中的 error 应该是什么类型? 开启相关严格选项后应按 unknown 处理,通过 instanceof Error 等方式确认后再读 message。
  • 追问:如何阻止 any 向核心代码扩散? 在边界立即用 unknown 接住并校验,缩小 any 所在函数范围,同时启用 noImplicitAny 和 lint 规则。

八、加强记忆

any 是“我不检查了”,unknown 是“我还不知道,先证明”,never 是“这里不该发生”。安全性排序上,unknown 通常比 any 更值得优先使用。

答题时再补上“边界输入用 unknown、穷尽分支用 never、any 只做受控逃生”,三个类型的工程位置就完整了。