为什么 TypeScript 不缩小数组类型?

Mat*_*een 3 narrowing typescript

为什么 TypeScript 不缩小数组类型?

function test(input: (string | number)[]): string[] {
  // The type of .map(...) reports that it returns string[].
  input = input.map(x => x.toString())
  // Type error: Type '(string | number)[]' is not assignable to type 'string[]'.
  return input
}
Run Code Online (Sandbox Code Playgroud)

解决方法并不依赖于通过立即使用或分配给新变量来缩小类型:

function test(input: (string | number)[]): string[] {
  return input.map(x => x.toString())
}

function test(input: (string | number)[]): string[] {
  const newInput = input.map(x => x.toString())
  return newInput
}
Run Code Online (Sandbox Code Playgroud)

我确实尝试过强制转换,但事后看来,这显然只适用于使用,例如return input as string[],并且不会缩小类型,因为.map(...)已经返回了正确缩小的类型。

必须执行这些解决方法对我来说感觉违反直觉。为什么 TypeScript 无法缩小此数组类型的范围,是否有更好的解决方法?

我确实查看了官方文档并查看了 Stack Overflow 上的类似问题,但除非我忽略了某些内容,否则我没有看到这个特定问题除了重新分配之外还有其他任何答案。

这就是我现在在自己的代码中所做的事情,但我只是希望我知道为什么会这样以及我是否可以做得更好。

> tsc --version                                                                                                                                                                                                                                                                              
Version 4.2.3
Run Code Online (Sandbox Code Playgroud)

jca*_*alz 7

无论好坏,基于赋值的缩小范围或通常通过控制流分析缩小范围(如在microsoft/TypeScript#8010中实现的那样 ,仅当涉及的变量具有联合类型时才会发生。通过联合类型,我的意思是类型本身直接是联合,像{a: string} | {a: number}Array<string> | Array<number>。具有联合类型属性的单个对象类型{a: string | number}本身不是联合;也不是interface使用联合类型类型参数指定的泛型,如。microsoft/TypeScript#16976Array<string | number>中有一个长期建议支持非联合控制流量缩小,但没有迹象表明何时或是否会实现。因此不会修改 的表观类型。input = input.map(x => x.toString())input

TypeScript 中还有其他缩小类型保护,例如in运算符或instanceof运算符,您可以编写自己的用户定义类型保护断言函数,以缩小其输入的类型。这些都对你没有多大帮助;如您所知,到目前为止,最好的解决方法就是不要重用同一变量来表示两种不同的非联合类型。