为什么在TypeScript中引入了“从不”类型?

Mor*_*sen 5 types typescript

我现在在互联网上搜索了为什么never要引入该类型的解释。TypeScript手册和TypeScript Deep Dive都说明了这是什么以及其他几篇文章。但是,他们都没有解释为什么要使用never类型及其解决方案。大多数示例都显示代码,编译器已经在其中推断出了位置never,那么为什么我必须分配类型?它能解决什么。是“只是”告诉我以后会做什么(即“无”-可能足够有用)。编译器将这些信息用于什么?与往常一样,对“什么”和“如何”的解释可能会帮助人们做事,但只有“为什么”才能使他们理解。

jca*_*alz 8

never类型是打字稿的的代表底部类型类型理论。因此,如果您正在寻找neverTypeScript的动机和用途,则可能通常需要研究计算机科学中的底层类型。


规范回答“为什么never推出打字稿”可能是最好通过分析在评论中发现介绍了它拉入请求:与这两个问题,它解决了一个底部类型的请求,并要求更好地处理可达函数返回

开发人员的主要用途是为函数(或函数的部分)提供一种类型,该类型根本不返回任何值,甚至不返回任何值undefined。比较这些功能:

function u(): undefined {
    return;
}
const uRet = u();
console.log(typeof uRet); // undefined

function v(): void { }
const vRet = v();
console.log(typeof vRet); // undefined
Run Code Online (Sandbox Code Playgroud)

undefined使用以下功能返回值:

function throws(): never {
    throw new Error();
}
const tRet = throws();
console.log(typeof tRet); // does not run

function loops(): never {
    while (true) { }
}
const lRet = loops();
console.log(typeof lRet); // does not run
Run Code Online (Sandbox Code Playgroud)

由于异常或死循环而根本不返回值。该never类型使开发人员和编译器都能推理出永远无法运行的代码段。


还有其他用途,never但由于您已经知道了代码示例,因此我不会尝试枚举它们。检查TypeScript标准库以找到never显示的地方很有启发性。


最后,当你问

大多数示例都显示代码,编译器已经在其中推断出了位置never,那么为什么我必须分配类型?

请注意,即使在编译器never为您推断的情况下,以语言形式存在也很有用,就像编译器推断出该代码一样string有用。对于何时需要显式注释类型而不是让编译器进行推断,反之亦然,这似乎是一个不同的问题。但是这篇文章已经很长了,可能在其他地方可以得到解答。

希望能有所帮助;祝好运!


编辑:never尽管许多程序员可能永远都不需要使用它,但是有很多原因会导致程序员会使用它。让我列举一些我能想到的原因:

  • 如果您正在为JavaScript库编写类型,在JavaScript库中函数会抛出异常而不是返回异常,所以如果没有,您将无法做到这一点never

  • 泛型类型参数默认为{}编译器无法推断出的类型。因为{}它与(几乎)所有值兼容,所以它有点“失败” 。在某些情况下,您希望它“关闭失败”并且不兼容任何值。您可以never用作默认参数。

  • 任何类型的工会Tnever只是T,和相交Tnevernever。这些规则(以及其他规则)使开发人员可以构建相当复杂的类型函数,而如果没有这些函数,则将变得更加困难或无法实现never。例如,这里是Diff<T,U>

    type Diff<T extends string, U extends string> =
      ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
    
    Run Code Online (Sandbox Code Playgroud)

    它是一个类型函数,它接受字符串文字的联合和字符串文字T的联合U,并返回所有T不在中的值的联合U

    您可以使用它来从类型中删除属性:

    type Foo = { a: string, b: number, c: boolean };
    type FooWithoutB = Pick<Foo, Diff<keyof Foo, 'b'>>;
    // equivalent to { a: string, c: boolean }
    
    Run Code Online (Sandbox Code Playgroud)

有点像数学中的零。您不需要它;在没有零概念的情况下,许多文化相处融洽。但这是非常有用的,它使您可以轻松表达原本笨拙或不可能的想法。

希望这更具吸引力吗?无论如何,再次祝你好运。