为什么在TypeScript中引入了`never`类型?

时间:2018-03-11 11:34:25

标签: typescript types

我现在已经在互联网上搜索了为什么never类型被引入的解释。 TypeScript手册和TypeScript Deep Dive都是它的本质和其他一些文章。但是,他们都没有解释,为什么要使用never类型及其解决的问题。 大多数示例都显示了代码,编译器已经推断出never,为什么我必须分配类型?它解决了什么。它是“仅仅”用信号表示智能感知之后我能做什么(即没有 - 这可能是有用的)。编译器使用什么信息? 和往常一样,对WHAT和HOW的解释可能会帮助人们做些什么,但只有为什么让他们理解。

1 个答案:

答案 0 :(得分:6)

never类型是TypeScript对bottom type type theory的表示。因此,如果您正在寻找TypeScript中never的动机和使用,您可能希望查看计算机科学中的底部类型。

为什么never被引入TypeScript"可能最好通过分析the pull request that introduced it上的评论及其解决的两个问题来找到:a request for a bottom typerequest to better handle unreachable function returns

开发人员的主要用途是拥有一个函数(或函数部分)的类型,它们根本不会返回任何值,甚至不会undefined。比较这些功能:

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

function v(): void { }
const vRet = v();
console.log(typeof vRet); // undefined

返回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
由于异常或无限循环,

根本不会返回值。 never类型允许开发人员和编译器推断出永远不会运行的代码段。

never还有其他用途,但我不会尝试枚举它们,因为您已经了解代码示例。检查TypeScript standard library以找到显示never的地方是很有启发性的。

最后,当你问

  

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

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

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

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

  • 如果您正在为JavaScript库编写一个函数抛出异常而非返回的函数,那么在没有{}的情况下您就无法做到这一点。

  • 通用类型参数默认为{},但编译器无法推断它们。由于never与(几乎)所有值兼容,因此它会打开"失败打开#34;有些情况下,您更喜欢“失败”和“关闭”。并且它与没有值兼容。您可以使用T作为默认参数。

  • 任何类型neverT的联合仅为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];

    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 }

    除其他外,您可以使用它从类型中删除属性:

         <div class="article-list">
             {% for article in issue.articles|slice:":4" %}
              <div class="section-article">
                <a href="{{ article.get_absolute_url }}"><p class="name">{{article.title}}</p></a>
    
                {% for author in article.contributors.all %}
                  <a href="{{ author.get_absolute_url }}"><p class="no-decoration author">{{ author.name }}</p></a>
                {% endfor %}
              </div>
             {% endfor %}
    
             <!-- if there are more than 5 articles in an issue -->
             {% if issue.articles|slice:"5:" %}
    
                <!-- create a collapse div -->
                 <div id="collapsearticle_{{ issue.id }}" class="collapse">
                   {% for article in issue.articles|slice:"5:" %}
                     <div class="section-article">
                       <a href="{{ article.get_absolute_url }}"><p class="name">{{article.title}}</p></a>
                       {% for author in article.contributors.all %}
                         <a href="{{ author.get_absolute_url }}"><p class="no-decoration author">{{ author.name }}</p></a>
                       {% endfor %}
                     </div>
                   {% endfor %}
                 </div>
    
                 <div class="text-center">
                   <div class="btn" data-toggle="collapse" data-target="#collapsearticle_{{ issue.id }}"> View more &#8964; </div>
                 </div>
    
             {% endif %}
    
           </div>

它有点像数学中的数字零。你不需要它;没有零概念,许多文化相处得很好。但它非常有用,可以让您轻松表达本来很麻烦或不可能的想法。

希望这更引人注目?无论如何,祝你好运。