为什么 TypeScript 在使用 concat 缩减数组时会推断出 'never' 类型?

Why does TypeScript infer the 'never' type when reducing an Array with concat?

代码胜于语言,所以:

['a', 'b', 'c'].reduce((accumulator, value) => accumulator.concat(value), []);

代码非常愚蠢,returns 一个复制的数组...

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

类型的参数

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

['a', 'b', 'c'].reduce((accumulator, value) => accumulator.concat(value), [] as string[]);

通常这不会是什么大问题,因为 TypeScript 在根据您对空数组的操作找出更好的类型分配给空数组方面做得不错。但是,由于您的示例是 'silly' 正如您所说的那样,TypeScript 无法进行任何推断并将类型保留为 never[].

更好的解决方案,避免类型断言(又名类型转换)的两个变体:

  1. 使用string[]作为reduce方法的泛型类型参数(感谢@depoulo提到):
['a', 'b', 'c'].reduce<string[]>((accumulator, value) => accumulator.concat(value), []);
  1. accumulator 值键入 string[](并且 避免在 [] 上进行类型转换 ):
['a', 'b', 'c'].reduce((accumulator: string[], value) => accumulator.concat(value), []);

尝试使用此解决方案 in the typescript playground

备注:

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

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

  3. 我在这里引用了我使用 Typescript 3.9.2 得到的整个错误消息,以便 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)
    

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

['a', 'b', 'c'].reduce<string[]>((accumulator, value) => accumulator.concat(value), []);

这会设置初始空数组的类型,我认为这是最正确的解决方案。

none 以上对我有用,即使将 tsconfig.json 文件更改为 "strict": false 并且只能通过以下方式避免破坏应用程序:

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore