为什么在第一个示例中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"
。
答案 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'
好的,希望能有所帮助。祝你好运!