为什么类型 "never" 在联合类型中没有意义?

Why is the type "never" meaningless in union types?

Typescript playground

我在思考类型 never 毫无意义并且在 联合类型 中时可以丢弃这一事实时遇到了一些麻烦.

我的意思是,我在 交集类型 中得到它,never 将立即使所有结果变为 never,因为某种类型无法实现和 never 在同一类型。这对我来说很有意义。

但是在 联合类型 中,我的直觉最初告诉我 never 类型是一个有效的选项。我的问题是为什么不呢?为什么 never 可以在联合类型中被丢弃?

谁能给我一个合理的解释,让我更好地理解它?

具体解释一下,type UNION_A = string | boolean | never的变量可以取boolean的任何有效值,string的任何有效值和never的任何有效值(其中没有值可以根据定义存在),因此具有 never 类型的联合不会对该变量可能最终接收的值域添加任何内容。

编辑: never 类型的要点是它是不可能发生的事情的类型,通常是 return 可以发生的函数类型不可能 return.

function fail() {
    throw new Error(":(");
    // What is the *return* type of that function?
}

let foo = fail(); // foo can only receive the type never
console.log(foo * 2); // Doesn't matter what foo is, this is guaranteed to be dead code

fail() 无法 return 一个值,甚至 null 也不可能。它可以 never return,因此它的 return 类型是 never,任何使用该函数的 return 值运行的代码基本上只是死代码。

never 的结合通常意味着你有这个

function do_thing(x) {
    let foo;
    if (x == 0) {
        fail(); // foo is of type never
    } else {
        foo = 1/x; // foo is of type number
    }

    // Foo is technically of type number | never,
    // but you can discard never since it never runs.
    let bar = foo * 2;
    return bar;
}

将类型视为可分配给它的所有值的 set 的一种方式。所以 boolean 可以被认为是 {true, false},这个集合只包含这两个值。 string 可以被认为是包含每个可能的 string 值的(本质上)无限集合。

在 TypeScript 中,never 就是 bottom type。它有 没有 值。如果你有一个 JavaScript 值并且你问“这是一个 never 类型的值吗?”那么答案是“不”。在集合方面,never可以被认为是∅,即 empty set.

类型到sets-of-values的映射中,intersection operation in TypeScript (&) can be thought of as the set intersection运算(∩)。如果你有集合 A 和 B,那么 A∩B 恰好是 both A and B 的成员的集合。对于任何集合A,A∩∅与空集的交集就是空集∅。 A 和空集中都没有元素,因为空集中根本没有元素。回到 TypeScript 类型,这意味着 A & never 对于任何类型 A 变成 never。如果 TypeScript 编译器只是将 string & never 保留为 string & never,那将是有效的,但实际上它会继续并自动将其缩减为 never,因为后者的表示更简单。

另一方面:在从类型到 sets-of-values 的映射中,union operation in TypeScript (|) can be thought of as the set union 操作 (∪)。如果你有集合 A 和 B,那么 A∪B 恰好是 either A or B 的成员的集合(这是包含 或)。对于任意集合A,A∪∅与空集的并集就是A。并集包含A的所有元素和空集的所有元素。由于没有空集的元素,这只是“A 的所有元素”。回到 TypeScript 类型,这意味着 A | never 对于任何类型 A 变成 A。如果 TypeScript 编译器只是将 string | never 保留为 string | never,那将是有效的,但实际上它会继续并自动将其缩减为 string,因为后者的表示更简单。

这就是基本的解释。还有其他的类比,比如布尔逻辑命题,比如“这个元素是这个类型的成员”,它对于 never 类型总是 FALSE,导致 A ∧ FALSE = FALSE 和 A ∨ FALSE = A。或者像算术,类比不精确,但交集看起来像乘法,联合看起来像加法(这个类比对对而不是交集和区分联合而不是常规联合变得精确)并且 never 类型是 0 . 但希望这能提供足够的直觉来解释为什么编译器会这样运行。

请注意,还有一个 top type in TypeScript called unknown which behaves exactly as the dual to never in that A & unknown = A and A | unknown = unknown and has the dual analog in set theory (the universal set/class)。但是你没有问这个,这个答案已经足够长了。