商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > TypeScript中never类型的神奇妙用

TypeScript中never类型的神奇妙用

  发布于2026-07-23 阅读(0)

扫一扫,手机访问

在 TypeScript 的类型系统里,never 绝对算得上一个“特立独行”的存在——它代表的是“永不存在的值类型”。简单说,就是那些根本不可能有结果的情况,比如抛异常的函数、无限循环,或者是在类型收窄时逻辑上永远走不到的分支。下面咱们就好好聊聊它的用法、妙处,以及一些容易踩坑的地方。

1. never 的用法

第一,抛出异常的函数。 当函数执行到一半直接 throw 一个错误,程序就此终止,不会再返回任何值,这时候返回类型就该写成 never

function throwError(message: string): never {
  throw new Error(message);
}

第二,死循环的函数。 比如一个永远跑不停的 while(true),它永远不会结束,自然也不会返回——never 正好适合它。

function infiniteLoop(): never {
  while (true) {}
}

第三,类型保护中的穷尽检查。 在类型缩小(type narrowing)的过程中,用 never 来标记那些理论上不可能出现的分支,能帮我们捕捉遗漏的情况,让代码更严谨。

function handleValue(value: string | number) {
  if (typeof value === 'string') {
    console.log('String value');
  } else if (typeof value === 'number') {
    console.log('Number value');
  } else {
    // 如果 value 类型是 never,编译器会检查这里的情况是否可能发生
    const _exhaustiveCheck: never = value;
    throw new Error('Unexpected type: ' + value);
  }
}
handleValue('string');
handleValue(1);
handleValue(true);

TypeScript中never类型的神奇妙用

2. never 的神奇

1. 确保类型全面覆盖。 在处理 switch 或多类型分支时,never 可以作为一个“强制检查工具”——如果你漏掉了某个分支,TypeScript 会在编译时报错。举个例子,有一个表示用户状态的联合类型:

type UserStatus = "active" | "inactive" | "banned";

function handleUserStatus(status: UserStatus) {
  switch (status) {
    case "active":
      console.log("User is active");
      break;
    case "inactive":
      console.log("User is inactive");
      break;
    case "banned":
      console.log("User is banned");
      break;
    default:
      // 强制类型检查是否已全面覆盖所有情况
      const exhaustiveCheck: never = status;
      throw new Error(`Unhandled status: ${status}`);
  }
}

关键就在 default 分支里:我们把 status 赋值给一个 never 类型的变量。如果后续 UserStatus 新增了一个成员(比如 'suspended'),而 switch 没处理它,TypeScript 就会报错——因为此时 status 不再是 never,而变成了 'suspended',赋值操作不通过。

type UserStatus = 'active' | 'inactive' | 'banned' | 'suspended';

TypeScript中never类型的神奇妙用

这样一来,只要有人新增了类型成员,编译器就会立刻提醒你“该补全分支了”,代码健壮性自然就上去了。

2. 类型收窄的辅助。 never 还能帮 TypeScript 判断哪些代码路径永远无法到达,从而优化类型检查和代码推理。比如可以用它来定义一个“排除某类型”的工具:

type MyExclude = T extends U ? never : T;

function isNumber(x: MyExclude) {}
isNumber('123')  // ok
isNumber({})     // ok
isNumber(true)   // ok
isNumber(111)    // 报错,因为 111 被 exclude 掉了

3. 判断 never 类型

这里有一个容易让人困惑的点:直接用条件类型判断 never 时,得到的结果往往不是你想要的。比如 T extends never ? true : false,当 Tnever 时,结果竟然是 never 而不是 true

为什么? 因为条件类型具有“分配式”(distributive)特性——当 T 是联合类型时,TypeScript 会把联合的每个成员分别代入条件。而 never 实际上是一个“空的联合类型”,没有成员,所以分配过程无法进行,直接返回 never

怎么解决?T 包在元组里,阻止分配式行为:

type IsNever = [T] extends [never] ? true : false;

这样 T 会作为一个整体参与判断,never 就能正确返回 true 了:

type Test1 = IsNever;       // true
type Test2 = IsNever;      // false
type Test3 = IsNever;   // false
type Test4 = IsNever;         // false

4. 注意事项

使用 never 时,有几个关键点需要留意:

  • 别滥用。 它只适用于“彻底没有结果”的场景。如果函数只是没有显式返回值(比如返回 undefined),用 void 更妥当。
  • 区别 void void 表示函数没有返回值,但调用后仍会得到 undefined;而 never 表示函数根本不会正常结束——要么抛异常,要么永远运行。
  • 善用类型收窄。 在穷尽检查分支时,never 能帮助 TypeScript 识别和优化代码路径。如果某个分支逻辑没有覆盖全,编译器会主动提醒你,防患于未然。
本文转载于:https://www.jb51.net/javascript/355903w50.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注