TypeScript 4.7回归:Array.flat(infinity)导致"类型示例化过于深入,可能是无限的,"错误

gojuced7  于 6个月前  发布在  TypeScript
关注(0)|答案(8)|浏览(74)

Bug报告

🔎 搜索词

  • Array.flat
  • 类型示例化过于深入,可能是无限的。
  • 嵌套数组

🕗 版本与回归信息

  • 在版本4.6和4.7之间发生了变化

⏯ Playground链接

带有相关代码的TypeScript Workbench

💻 代码

interface Config {
  prop?: string;
}

interface ExtendedConfig extends Config {}

type NestedConfigs = Array<ExtendedConfig | NestedConfigs>;

const configs: NestedConfigs[] = [];

const flattened = configs.flat(Infinity);

🙁 实际行为

对于 configs.flat(Infinity) 调用,TypeScript会引发以下错误:
Type instantiation is excessively deep and possibly infinite. ts(2589)

🙂 预期行为

不应引发错误。

ercv8c1e

ercv8c1e1#

今天在4.7.2版本中也遇到了这个问题。在4.6版本中,输出被错误地显示为any[](playground)。

ogq8wdun

ogq8wdun2#

在从4.6.4升级到4.7.2的过程中,也遇到了这个问题。整个应用程序无法编译。

qq24tv8q

qq24tv8q3#

刚刚也遇到了这个问题,这里有一个非常简洁的例子:

type StringOrStringArray = string | StringOrStringArray[];

const flatten = (...args: StringOrStringArray[]) => args.flat(Infinity);

args.flat(Infinity) 上出现了完全相同的错误,"类型示例化过于深入,可能是无限的。"
目前快速的解决方案是将你的 .flat 参数Assert为整数:
args.flat(Infinity as 10)
这应该会使错误消失。

rkue9o1l

rkue9o1l4#

我不太确定如何对此进行推理。这个错误在所有情况下都是正确的。你可以写

interface Config {
  prop?: string;
}

interface ExtendedConfig extends Config {}

type NestedConfigs = Array<ExtendedConfig | NestedConfigs>;

const configs: NestedConfigs[] = [];
configs.push(configs); // <- legal
const flattened = configs.flat(Infinity); // <- crashes at runtime

这会导致

VM273:1 Uncaught RangeError: Maximum call stack size exceeded
    at Array.flat (<anonymous>)
    at <anonymous>:1:5

如果你有一个有限深度(T | T[])[],那么最好将一个有限参数传递给 flat 。如果你确信深度实际上是由某个不可知的高精度整数(????)限制的,那么对 Infinity 进行类型Assert到一个较低的整数(我强烈建议使用 1 ,而不是 10 ,因为它们实际上执行不同级别的解包),这似乎是合适的Assert,因为你比 TypeScript 对这种情况下的数据结构了解更多。

ttvkxqim

ttvkxqim5#

我不确定我认为正确的输出类型是什么,但在我看来,TypeScript编译器应该允许 .flat(Infinity)(没有类型Assert)而不直接失败编译,因为它是有效的和常见的JavaScript(例如MDN上的示例)。
也许将 Infinity 特殊处理以得到 unknown[]any[] 是合理的?

c9qzyr3d

c9qzyr3d6#

我应该也指出,作为一个TypeScript的用户,"可能无限"的东西对我来说是有足够意义的,但我对如何绕过类型错误有点困惑,因为这种错误阻止了像configs.flat(Infinity) as Config[]这样的后置转换。

gstyhher

gstyhher7#

Type-asserting Infinity to a lower integer (I'd really recommend 1 , not 10 , as they actually do different levels of unwrapping) if you're confident that the depth is actually bounded by some unknowably-high integer (????) seems like an appropriate assertion, since you know more than TypeScript does about the data structure in this case.
Oh, that's really interesting, I actually didn't know that. So to get more specific, in my use case I was actually using it within a function that allows one to optionally declare a flattening depth. To go off of my example, that might look like:

type StringOrStringArray = string | StringOrStringArray[];

const curriedFlatten = (depth = 10) => (...args: StringOrStringArray[]) => args.flat(depth); // <--- Same instantiation error

The intent here was to mimic something like a flat(Infinity) , Hence the assertion to a higher integer. I'm assuming that because in this instance depth can be Infinity , that it gives that error. If TS treats the type-assertion with different levels of unwrapping, it might be worth it to lower that depth instantiation just for those gains.
I tend to agree with @grant-dennison above, it seems like .flat(Infinity) feels commonplace enough to warrant TypeScript handling this in a way that makes sense with (T | T[])[] types for flattening them. That being said, I do see how that gets very hairy, very fast.
A potential middle-ground here may be some form of 'non-infinite' integer or number type. To go back to my example:

type StringOrStringArray = string | StringOrStringArray[];

const fancyFlatten = (depth: NonInfiniteNumber, ...args: StringOrStringArray[]) => args.flat(depth);

That way I can tell TypeScript that this is actually bounded by some unknowably-high integer, and have type errors if I try to call fancyFlatten with Infinity

nue99wik

nue99wik8#

如果为 Infinity 添加了字面类型,这个问题就可以得到解决:使用 1e309 的 playground link。

相关问题