字符串文字的 TypeScript 推断

moc*_*cha 10 typescript

我的问题很简单。鉴于此代码:

const array = [1, 2, 3, 4, 5];
const map01 = array.map((v) => v % 2 ? "" : "");
//    ^? string[]
const map02 = array.map((v) => v % 2 ? "odd" : "even");
//    ^? ("odd" | "even")[]
const map03 = array.map((v) => v % 2 ? "!" : "");
//    ^? ("" | "!")[]
Run Code Online (Sandbox Code Playgroud)

为什么 TypeScript 会做出如此奇怪的推论?不应该map01被推断为""[]

操场

在此输入图像描述

jca*_*alz 10

有关文字类型加宽如何以及何时发生的详细信息,请参阅microsoft/TypeScript#10676。它特别指出:

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

因此,这意味着在 的情况下"odd" | "even",您有一个未加宽的文字联合类型,而在 的情况下,您有一个""加宽的非联合文字类型。

至于为什么使用这条规则而不是更简单的“从不扩大”规则,这是一个启发式的选择,旨在最大限度地减少“正常”情况下的意外。文字类型通常在联合中比单独使用更有用,因此编译器假设function foo() {return "abc"}更有可能返回string,而function bar() {return Math.random<0.5 ? "abc" : "def"}更有可能返回文字的联合。作为一种启发式方法,它并不完美,但它显然比其他方法引起的惊喜要少。

GitHub 中存在各种问题,当前行为被视为按预期工作;例如,请参阅带有以下评论的microsoft/TypeScript#51551

扩大规则是为了启发式地尝试推断“更好”的类型,并且允许不同的代码在这些启发式下有不同的行为