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

x7rlezfr  于 2022-12-05  发布在  TypeScript
关注(0)|答案(6)|浏览(469)

代码比语言更能说明问题,因此:

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

代码很傻,返回一个复制的Array...
TS抱怨concat的论点:TS2345:类型“string”的参数不能赋给类型“ConcatArray”的参数。

b09cbbtk

b09cbbtk1#

我相信这是因为[]的类型被推断为never[],这是一个必须为空的数组的类型。

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

通常情况下,这不会是什么大问题,因为TypeScript会根据您对空数组的处理,很好地为空数组指定一个更好的类型。然而,由于您的示例像您所说的那样“愚蠢,”TypeScript无法进行任何推断,并将类型保留为never[]

l7wslrjt

l7wslrjt2#

一个更好的解决方案,避免了类型Assert(又名类型转换),有两种变体:
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), []);

在 typescript 游戏场中使用此解决方案。

备注

1.类型Assert(有时称为 * 类型强制转换 *)应尽量避免,因为您要采用一种类型并将其转置为其他类型。这可能会导致副作用,因为您要手动控制将变量强制转换为另一种类型。
1.只有当strictNullChecks选项设置为true时,才会出现此类型脚本错误。禁用该选项时,类型脚本错误会消失,但这可能不是您所希望的。
1.我在这里引用了我在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)
im9ewurl

im9ewurl3#

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

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

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

alen0pnh

alen0pnh4#

您可以使用泛型型别来避免这个错误。
查看我的展平函数示例:

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

kxkpmulp5#

以上这些对我都不起作用,即使将tsconfig.json文件修改为“strict”:false,只能通过以下方式避免中断应用程序:

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

tct7dpnv6#

设置类型的另外两种方法比类型转换(即[] as string)更让我喜欢:

  • <string[]>[]
  • Array<string>(0)

相关问题