如何解释 TypeScript 中 any、unknown 和 never 类型的区别?

讨论了 TypeScript 中 any、unknown 和 never 类型的区别,包括它们的特性、风险和适用场景。

TypeScript 中等 类型系统 类型

anyunknownnever 是 TypeScript 中的特殊类型,核心区别如下:

1. any

  • 特性:禁用类型检查,可赋值给任意类型,也可接受任意值。
  • 风险
    • 导致类型污染(后续操作均视为 any)。
    • 允许访问不存在的属性或方法而不报错(编译时跳过检查)。
  • 适用场景:临时兼容动态内容或旧代码迁移(但应尽量避免)。
  • 示例
    let val: any = "hello";  
    val = 123;               // 无错误  
    val.nonExistingMethod(); // 编译通过(运行时可能出错)  
    

2. unknown

  • 特性:类型安全的 any 替代品:
    • 可接受任意值,但不能直接操作
    • 必须通过类型守卫类型断言收缩类型后才可安全使用。
  • 优势:规避 any 的类型污染问题。
  • 适用场景:处理外部数据(如 API 响应或用户输入)等未知类型。
  • 示例
    let data: unknown = fetchExternalData();  
    // data.toUpperCase(); // 直接调用报错!  
    if (typeof data === "string") {  
      data.toUpperCase();  // 通过类型守卫安全使用  
    }  
    

3. never

  • 特性:表示永不存在的值
    • 不可赋值任何值(除了 never 自身)。
    • 可以赋值给任意其他类型(因为该值永远不会出现)。
  • 适用场景
    • 函数抛出异常或死循环(永不返回)。
    • 类型运算中排除不可能的分支(如条件类型中的 Exclude<T, U>)。
  • 示例
    function throwError(msg: string): never {  
      throw new Error(msg); // 永不返回值  
    }  
    let num: number = throwError("fail"); // 允许(实际无返回值)  
    

三者的核心区别对比表

特性 any unknown never
接受赋值 ✅ 任意类型 ✅ 任意类型 ❌ 仅 never 自身
赋值给其他类型 ✅ 所有类型 ❌ 仅 anyunknown ✅ 所有类型(永不出现)
直接操作属性/方法 ✅(无类型检查) ❌ 需先收缩类型 ❌(无值可操作)
类型安全 ❌(高风险) ✅(需显式类型检查) ✅(表示不可能的值)

最佳实践:优先用 unknown 替代 any 保证安全;在不可能返回的场景用 never;严格限制 any 的使用。