打字稿中的never和void有什么区别?

iro*_*nic 43 typescript

我已经读过这个,但是不清楚'never'和'void'类型之间有什么区别?

Rya*_*ugh 22

为了增加Lee的非常好的答案,另一种思考方式是在正确类型的程序中,无法观察到never值.

除了永不返回的函数(或者总是抛出异常的函数)之外,never当联合类型已经用尽其所有可能的成分时,您将看到类型:

// Example assumes --strictNullChecks
function fn(x: number | string) {
  if (typeof x === 'number') {
    // x: number in this block
  } else if (typeof x === 'string') {
    // x: string in this block
  } else {
    // x: never in this block
    // this block does not run; the value of x cannot be observed
  }
}
Run Code Online (Sandbox Code Playgroud)

  • “永远不能观察到价值”:我认为'void'价值是一样的,不是吗? (2认同)

Lee*_*Lee 21

在命令式语言中,void可以将其视为包含单个值的类型.这些语言不提供构造或使用此值的方法,但void可以将函数视为返回此微不足道的值.

相反,never是一个不包含值的类型,这意味着具有此返回类型的函数根本无法正常返回.这意味着抛出异常或未能终止.

  • 在大多数命令式语言中,"void"不正确.在那些语言中,`void` _is_是底部类型,它没有确切的值(例如,函数参数不能是'void`类型).答案将底部类型与_unit type_混淆. (2认同)
  • @FrankHB - 如果这是真的,那么具有 `void` 返回类型的函数根本不会返回,这不一定是这种情况。在这些语言中调用 `void` 函数是一个语句,在 Rust、F# 等面向表达式的语言中,语句被映射到类型为 `unit` 的表达式。 (2认同)
  • 好吧,我会重构我的话。反对意见是针对你的第一个陈述。正如您所说,“在命令式语言中”,命令式语言应该是_对象语言_(例如这里的 Typescript)。您的声明表明它们的规则允许“void”类型作为真正的单位类型,但这不是事实(例如在我给出的情况下)。此外,只要您忽略实现实际如何利用该类型,将“void”视为单元类型就根本没有帮助(如果不会造成混淆)。 (2认同)
  • 大多数此类语言(至少是 C 语言)都将“void”作为静态类型之一,由类型检查器强制处理。应通过对错误类型的表达式进行类型检查来检测违规行为。这与对象语言中被调用函数的终止无关,即使它确实使翻译(包括类型检查)无法正常终止。不过,由于诊断规则的附加要求,转换应该终止。在翻译中用单元类型替换“void”以使其始终终止是一个实现细节。 (2认同)

Waj*_*ath 11

正如Marius Schulz 在本文中讨论的那样

  • 未显式返回值的函数会隐式返回undefinedJavaScript 中的值。尽管我们通常说这样的函数“不返回任何内容”,但它会返回。在这些情况下,我们通常会忽略返回值。这样的函数void在 TypeScript 中被推断具有返回类型。
  • 具有never返回类型的函数永远不会返回。它也不会返回 undefined。该函数没有正常完成,这意味着它会抛出错误或根本没有完成运行。

  • 感谢您的补充,这对我来说是最好的答案 (3认同)

Prz*_*ski 9

从来没有信息表明该特定部分不应该访问。例如在这段代码中,

function do(): never {
    while (true) {}
}
Run Code Online (Sandbox Code Playgroud)

你有一个无限循环,我们不想迭代无限循环。就这么简单。

但真正的问题是它对我们有何用处?例如,在创建更高级的类型时指出它们不是什么可能会有所帮助

例如,让我们声明我们自己的 NonNullable 类型:

type NonNullable<T> = T extends null | undefined ? never : T;
Run Code Online (Sandbox Code Playgroud)

这里我们检查 T 是否为空或未定义。如果是的话,我们就指出它永远不应该发生。然后在使用这种类型时:

let value: NonNullable<string>;
value = "Test";
value = null; // error
Run Code Online (Sandbox Code Playgroud)

void是这样的信息:该类型的函数不返回任何值,但它们是可访问的并且可以使用。


Amr*_*oub 7

该类型绝不意味着什么也没有发生。当类型保护无法发生时,或者总是抛出异常的情况下,使用它。无效和从不之间有区别。显式返回类型 never won\xe2\x80\x99t 的函数允许返回未定义,这与允许返回未定义的 void 函数不同。

\n\n
function functionThrow(): never {\nthrow new Error("This function return never");\n
Run Code Online (Sandbox Code Playgroud)\n\n

}

\n\n

例如,在下面的代码中,有一个包含两个项目的枚举。TypeScript 知道只有两种情况可能发生,默认(其他)情况不会发生。TypeScript 的这种见解是完美的,因为函数返回类型只接受字符串,而不接受 never。如果将来您从枚举中添加新项目(例如,在 switch 语句中没有添加新 case 的 ChoiceC),则代码可以调用从不返回的 unhandledChoice 函数。

\n\n
 enum EnumWithChoices {\n    ChoiceA,\n    ChoiceB,\n    ChoiceC,\n}\n\nfunction functionReturnStringFromEnum(c: EnumWithChoices): string {\n    switch (c) {\n        case EnumWithChoices.ChoiceA:\n            return "A";\n        case EnumWithChoices.ChoiceB:\n            return "B";\n        default:\n            return unhandledChoiceFromEnum(c);\n    }\n}\n\nfunction unhandledChoiceFromEnum(x: never): never {\n    throw new Error("Choice not defined");\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后,never 表示不应该出现的状态。异常不是预期的行为。函数中的无限循环并不意味着在系统中是可持续的,从未访问过的条件不应该存在。

\n


小智 6

另外,对于更多的理论原因,使用--strictNullChecks新标志,TypeScript需要一个新的底部类型(因为null并且undefined不再是).类型never是这样的底部类型,使TypeScript的类型系统更加一致.


小智 6

简而言之:

void返回voidnever永不返回。

  • 你不能真正“返回void”。它*意味着*它“不返回任何内容”,但因为JavaScript是JavaScript,它实际上返回的是“未定义”*但是*你不应该*使用*任何东西的返回值,你应该假装没有一。 (2认同)

FUJ*_*oro 5

的返回类型Promise.reject()Promise<never>,意思是“它永远不会被解析”。

因此,如果函数返回Promise<never>,我认为它只会返回错误。另一方面,Promise<void>解决问题可能没有任何价值。