如何使用 never 类型

  1. 由于永远不能给 never 类型赋值,所以可以用它来对各种函数用例施加限制;
  2. 目的就是写出类型绝对安全的代码 (代码错误,提示改错)

确保对 switch 和 if-else 语句中的所有条件都做处理

  1. 如果一个函数只能接受一个 never 的参数,那么这个函数就永远不能用任何非 never 的值来调用 (不传 never 类型 TypeScript 编译器会发出警报)

  2. 可以用这类函数来确保 switchif-else 语句中,每个条件都覆盖了处理方法:将其放在 default 条件中,可以确保每个条件都被处理,否则取值必须是 never 类型,如果不小心漏掉了一个可能的条件,会得到一个类型错误,如下:

function unknownColor(x: never): never {
  throw new Error("unknown color");
}

// Color 新增了一个 blue' 类型,getColorName 中没有进行处理
type Color = 'red' | 'green' | 'blue'

function getColorName(c: Color): string {
  switch (c) {
    case 'red':
      return 'is red';
    case 'green':
      return 'is green';
    default:
      // const unknownColor: never = c; // 等价
      return unknownColor(c); // ❌ Argument of type 'string' is not assignable to parameter of type 'never'
  }
}

禁用结构化类型中的一部分

  1. 假设有一个函数,它接受一个 VariantA 类型或 VariantB 类型的参数,但是不能接受一个同时包含两种类型所有属性的类型,即两种类型的一个子类型;

  2. 使用 never 后,就可以将类型结构中的部分给禁用掉,从而阻止用户向其传递包含两种类型属性的对象;

type VariantA = {
  a: string
  b?: never // 使用 never 限制
}
type VariantB = {
  b: number
  a?: never // 使用 never 限制
}
declare function fn(arg: VariantA | VariantB): void

fn({ a: 'foo' }) // ✅
fn({ b: 123 }) // ✅
fn({ a: 'foo', b: 123 }) // ❌ Types of property 'a' are incompatible

用于表示理论上无法到达的条件分支

当在条件类型中使用 infer 创建一个类型变量时,必须为每个 infer 关键字创建 else 分支:

type A = 'foo';

type B = A extends infer C
  ? (C extends 'foo' ? true : false)  // 在此表达式中,C 等同于 A
  : never // 这个分支永远不会执行,但是也不能不写它

从映射类型中过滤属性

  1. TypeScript 中,类型是不可变的,如果想要从一个对象类型中删除一个属性,可以通过新建一个类型、转换和过滤达到这个目的,而我们只要在映射类型中用条件做重映射就可以达到相同的效果;

  2. 以下 Filter 类型,是基于 对象类型的值对象类型 进行筛选的例子:

type Filter<Obj extends Object, ValueType> = {
  [Key in keyof Obj as (ValueType extends Obj[Key] ? Key : never)]: Obj[Key]
}

interface Foo {
  name: string;
  id: number;
}

// 过滤 Foo,留下 string 类型的字段
type Filtered = Filter<Foo, string>; // { name: string }
// 过滤 Foo,留下 number 类型的字段
type Filtered2 = Filter<Foo, number>; // { id: number }
// 过滤 Foo,留下 boolean 类型的字段
type Filtered3 = Filter<Foo, boolean>; // { }

如何检查类型推导是否为 never

  1. 检查一个类型是否会推导为 never 比想象中要难得多,思考以下代码:

    type IsNever<T> = T extends never ? true : false
    type Res = IsNever<never> // never 🧐,淦
    
  2. 原因可以总结为:

    1. TypeScript 会自动将联合类型分发为条件类型;
    2. never 是一个空联合类型;
    3. 因此,当分发发生时,没有内容可分发,所以条件类型再次将其推导为 never
  3. 唯一的解决方法是不使用隐式分发,而是将类型参数封装在一个元组中:

    type IsNever<T> = [T] extends [never] ? true : false;
    type Res1 = IsNever<never> // 'true' ✅
    type Res2 = IsNever<number> // 'false' ✅
    
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

中午好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 如何使用 never 类型
    1. 1.1. 确保对 switch 和 if-else 语句中的所有条件都做处理
    2. 1.2. 禁用结构化类型中的一部分
    3. 1.3. 用于表示理论上无法到达的条件分支
    4. 1.4. 从映射类型中过滤属性
  2. 2. 如何检查类型推导是否为 never