打字稿类型推断和文字类型

时间:2019-09-23 11:18:02

标签: typescript

为什么在第一个示例中Typescript会推断类型string,而在第二个示例中它能够推断类型文字'good' | 'bad'的精确类型并集呢?

const alwaysSomething = () => 'something' // inferred returned type: string
const moreComplicated = (mark: number) => mark >= 10 ? 'good' : 'bad' // inferred returned type:  'good' | 'bad'

On the playground。如果您将鼠标悬停在alwaysSomething上,则其类型为() => string,但是如果您将鼠标悬停在moreComplicated上,则其类型为(mark: number) => "good" | "bad"

1 个答案:

答案 0 :(得分:3)

对于这个问题的规范答案(如果有的话)很可能会在pull request implementing the literal widening algorithm中找到。首先,我们可以看到您所看到的行为是预期的:

  

在没有返回类型注释的函数中,如果推断的返回类型是文字类型(但不是文字联合类型),并且该函数不具有上下文类型且其返回类型包括文字类型,则返回类型扩展到其扩展的文字类型。

推断的返回类型() => 'something'是文字"something",然后将其扩展为string。另一方面,(mark: number) => mark >= 10 ? 'good' : 'bad'的推断返回类型为"good" | "bad",它是文字联合类型,因此不会扩展。

为什么单值文字扩展了?作者this comment

  

[Y] ou实际上从不想要文字类型。毕竟,为什么要编写一个保证始终返回相同值的函数?另外,如果我们推断文字类型,则该常见模式将被破坏:

class Base {
  getFoo() {
      return 0;  // Default result is 0
  }
}

class Derived extends Base {
  getFoo() {
      // Compute and return a number
  }
}
     

如果我们为0中的返回类型推断类型Base.getFoo,则用实际计算数字的实现来覆盖它是错误的。如果您确实要返回文字类型,即getFoo(): 0 { return 0; },当然可以添加类型注释。

为什么不扩大字面的并集呢?这是作者的a later comment

  

对于return cond ? 0 : 1,推断的返回类型将为0 | 1。我认为在这种情况下,我们应该扩展到基本原始类型尚不清楚。毕竟,对于返回类型为0 | 1,实际上有有意义的信息从函数中传递出来。

因此,问题是实用性之一:人们很少打算返回单个文字类型,但是他们通常确实打算返回文字类型的并集。由于类型推断总是可以由显式类型注释覆盖,因此您可以处理这种启发式方法给您带来错误的情况:

const alwaysSomething = (): 'something' => 'something' // inferred returned type: 
const moreComplicated = (mark: number): string => mark >= 10 ? 'good' : 'bad'

好的,希望能有所帮助。祝你好运!