1. 引用
      1. ts any、unknown、object、void、undefined、null 和 never 的类型兼容性
      2. ts Top Type、Bottom Type
    2. 术语
      1. 死代码(Dead Code)
    3. never 类型被称为 Bottom Type,是整个类型系统层级中最底层的类型。
    4. never 类型的类型兼容性
      1. never 类型的值可以赋值给任何类型
      2. 只有 never 类型才能赋值给 never 类型
    1. const neverVar = 'never' as unknown as never
    2. const x1: number = neverVar
    3. const x2: string = neverVar
    4. const x3: boolean = neverVar
    5. const x4: symbol = neverVar
    6. const x5: undefined = neverVar
    7. const x6: null = neverVar
    8. const x7: object = neverVar
    9. const x8: any = neverVar
    10. const x9: never = neverVar
    11. // ...
    1. never 的常见应用场景
      1. 使用 never 约束函数返回类型
      2. never 与联合类型结合使用
    2. 用 never 来约束函数返回类型时,函数体需要满足一定的要求才行,否则会报错
    1. // error
    2. function foo(): never { }

    如果将返回类型约束为 never,意味着我们的函数体实现不能乱来,还必须满足一些潜规则才行。

    1. never 表示永远不会发生,如果你想要表达一个函数执行后将永远不会结束、永远不会有结果、甚至导致程序直接终止运行,那么你可以用 never 来约束函数的返回类型。
    2. 如果想要表达函数永远不会结束,可以使用 never 类型来约束函数的返回结果
      1. 一个函数负责抛出错误,你调用它之后,将永远无法拿到该函数的返回值,此时,该函数的返回值类型就可以写作 never
      2. 一个函数在执行过程中陷入死循环,此时也可以将返回值类型写作 never
    1. function throwError(message: string): never {
    2. throw new Error(message);
    3. }
    1. function infiniteLoop(): never {
    2. while (true) {
    3. // ...
    4. }
    5. }

    一些微不足道的细节 死循环中如果出现非 Dead Code 的 break 语句,返回值约束为 never 将会报错。

    image.png
    image.png
    image.png

    死循环还必须得使用 true,如果是其它值,比如 1,默认也是不被允许的。

    image.png

    除了支持用 while 表示死循环,ts 也允许我们用 for 来表示死循环。

    image.png

    1. 如果一个函数的返回值是 never 类型,那么该函数的调用语句之后的代码将被推断为 Dead Code
    1. function throwError(message: string): never {
    2. throw new Error(message);
    3. }
    4. function foo() {
    5. throwError("undefined error");
    6. // Dead Code
    7. console.log("hello");
    8. console.log("world");
    9. }

    Dead Code 表示死代码、无效的代码。在 vscode 中,Dead Code 默认会被置灰,以此来提醒我们这部分的程序很可能是无意义的,它们将永远不会被执行。

    image.png

    1. never 表示不应该出现的值,当 ts 判断联合类型中没有其它类型可选时,也会出现 never 类型。
    1. function fn(x: string | number) {
    2. if (typeof x === "string") {
    3. // x: string
    4. } else if (typeof x === "number") {
    5. // x: number
    6. } else {
    7. // x: never
    8. throw new Error(`Unknown input type: ${x}`);
    9. }
    10. }

    由于 ts 强大的类型分析能力,每经过一个 if 语句处理,x 的类型分支就会减少一个。在最后的 else 代码块中,它的类型只剩下了 never 类型,即一个无法再细分、本质上并不存在的虚空类型。

    1. 你可以把 never 视作一个“不存在”的类型
    1. type UnionWithNever = 123 | "abc" | true | void | never;
    2. // 将鼠标悬停在 UnionWithNever 上,查看 ts 推导出来的结果:
    3. // type UnionWithNever = true | void | 123 | "abc"
    4. // 会发现 never 类型直接被无视了

    当 never 出现在联合类型中时,它就像一个空集合,不会对联合类型的其他部分产生任何影响。

    1. 未标明类型的数组,可能会被推断为 never 类型
    1. // 默认配置
    2. const arr = []
    3. // const arr: any[]
    4. // 开启 strictNullChecks 配置,同时禁用 noImplicitAny 配置
    5. const arr = []
    6. // const arr: never[]