简体   繁体   English

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

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

Code speaks better than language, so:代码比语言说得更好,所以:

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

The code is very silly and returns a copied Array...该代码非常愚蠢,并返回一个复制的数组......

TS complains on concat's argument: TS2345: Argument of type 'string' is not assignable to parameter of type 'ConcatArray'. TS 抱怨 concat 的参数:TS2345:“字符串”类型的参数不可分配给“ConcatArray”类型的参数。

I believe this is because the type for [] is inferred to be never[] , which is the type for an array that MUST be empty.我相信这是因为[]的类型被推断为never[] ,这是必须为空的数组的类型。 You can use a type cast to address this:您可以使用类型转换来解决此问题:

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

Normally this wouldn't be much of a problem since TypeScript does a decent job at figuring out a better type to assign to an empty array based on what you do with it.通常这不是什么大问题,因为 TypeScript 在根据您对空数组的处理方式找出更好的类型以分配给空数组方面做得不错。 However, since your example is 'silly' as you put it, TypeScript isn't able to make any inferences and leaves the type as never[] .但是,由于您的示例正如您所说的那样“愚蠢”,因此 TypeScript 无法进行任何推断并将类型保留为never[]

A better solution which avoids a type assertion (aka type cast) in two variants:一种更好的解决方案,可以避免两种变体中的类型断言(又名类型转换):

  1. Use string[] as the generic type parameter of the reduce method (thanks @depoulo for mentioning it):使用string[]作为reduce方法的泛型类型参数(感谢@depoulo 提及):
['a', 'b', 'c'].reduce<string[]>((accumulator, value) => accumulator.concat(value), []);
  1. Type the accumulator value as string[] (and avoid a type cast on [] ):accumulator值键入为string[] (并避免[]上进行类型转换):
['a', 'b', 'c'].reduce((accumulator: string[], value) => accumulator.concat(value), []);

Play with this solution in the typescript playground . 在 typescript playground 中使用此解决方案。

Notes :备注

  1. Type assertions (sometimes called type casts ) should be avoided if you can because you're taking one type and transpose it onto something else.如果可以的话,应该避免使用类型断言(有时称为类型转换),因为您正在采用一种类型并将其转换为其他类型。 This can cause side-effects since you're manually taking control of coercing a variable into another type.这可能会导致副作用,因为您手动控制将变量强制转换为另一种类型。

  2. This typescript error only occurs if the strictNullChecks option is set to true .仅当strictNullChecks选项设置为true时才会发生此打字稿错误。 The Typescript error disappears when disabling that option, but that is probably not what you want.禁用该选项时,Typescript 错误会消失,但这可能不是您想要的。

  3. I reference the entire error message I get with Typescript 3.9.2 here so that Google finds this thread for people who are searching for answers (because Typescript error messages sometimes change from version to version):我在这里引用了我使用 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)

You should use generics to address this.您应该使用泛型来解决这个问题。

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

This will set the type of the initial empty array, which in my opinion is the most correct solution.这将设置初始空数组的类型,我认为这是最正确的解决方案。

none of the above worked for me, even with altering the tsconfig.json file to "strict": false and was only able to avoid breaking the application with the following:即使将 tsconfig.json 文件更改为 "strict": false 并且只能避免使用以下内容破坏应用程序,上述方法均不适合我:

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

You can use Generic type to avoid this error.您可以使用通用类型来避免此错误。

Check my example of flatten function:检查我的展平 function 的示例:

export const flatten = <T>(arr: T[]): T[] => arr.reduce((flat, toFlatten) =>
  (flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten)), [] as T[]);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM