为什么使用concat减少数组时TypeScript会推断“从不”类型?

pir*_*-gh 11 reduce functional-programming reducers typescript

代码胜于语言,因此:

['a', 'b', 'c'].reduce((accumulator, value) => accumulator.concat(value), []);
Run Code Online (Sandbox Code Playgroud)

该代码非常愚蠢,并返回一个复制的数组...

TS抱怨concat的参数:TS2345:类型'string'的参数不能分配给'ConcatArray'类型的参数。

And*_*dru 16

避免类型转换的更好解决方案:

键入accumulator的值作为string[](和避免一个类型转换[]):

['a', 'b', 'c'].reduce((accumulator: string[], value) => accumulator.concat(value), []);
Run Code Online (Sandbox Code Playgroud)

在打字稿游乐场中使用此解决方案。

注意事项

  1. 如果可以,应该避免类型转换,因为您正在采用一种类型并将其转换为其他类型。这可能会导致副作用,因为您手动控制将变量强制转换为另一种类型。

  2. 此打字稿错误仅在该strictNullChecks选项设置为true. 禁用该选项时,Typescript 错误会消失,但这可能不是您想要的。

  3. 我在3.9.2此处引用了使用 Typescript 获得的整个错误消息,以便 Google 为正在搜索答案的人找到此线程(因为 Typescript 错误消息有时会因版本而异):

    No overload matches this call.
      Overload 1 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
     Argument of type 'string' is not assignable to parameter of type 'ConcatArray<never>'.
      Overload 2 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
     Argument of type 'string' is not assignable to parameter of type 'ConcatArray<never>'.(2769)
    
    Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案。稍微不同的解决方案,使用泛型: `['a', 'b', 'c'].reduce&lt;string[]&gt;((accumulator, value) =&gt; Accumulator.concat(value), []);` (3认同)

Mat*_*t H 12

我相信这是因为for的类型[]推断为never[],这是必须为空的数组的类型。您可以使用类型强制转换来解决此问题:

['a', 'b', 'c'].reduce((accumulator, value) => accumulator.concat(value), [] as string[]);
Run Code Online (Sandbox Code Playgroud)

通常,这不会有太大问题,因为TypeScript会根据您的操作在确定更好的类型以分配给空数组方面做得不错。但是,由于您的示例如前所述是“傻”的,因此TypeScript无法进行任何推断,并将类型保留为never[]

  • “为什么 TypeScript 会推断出 'never' 类型?” “因为`[]` 的类型被推断为`never[]`”。如果是这样,那么为什么 `const array = [];` 将 `array` 推断为类型 `any[]`? (2认同)
  • 相关:https://github.com/Microsoft/TypeScript/issues/18687 它比我意识到的要复杂,但是在上下文输入时,`[]` 被推断为某种“扩展 `any[]`”类型......显然,在作为“reduce()”中的累加器传递时不会发生这种情况。‍♀️ (2认同)

the*_*eva 9

您应该使用泛型来解决这个问题。

['a', 'b', 'c'].reduce<string[]>((accumulator, value) => accumulator.concat(value), []);
Run Code Online (Sandbox Code Playgroud)

这将设置初始空数组的类型,在我看来这是最正确的解决方案。