传播参数的不一致 TypeScript 错误

Inconsistent TypeScript error for spread arguments

对于此函数:

function foo(a: number, b: number) {/* ... */}

代码段 1 导致错误:

foo(1, ...[]);

Expected 2 arguments, but got 1 or more.

代码段 2 导致错误:

foo(1, 2, ...[]);

Expected 2 arguments, but got 3 or more.

看起来奇怪的是第二种情况不是 "got 2 or more"。该代码不会尝试解决任何特定问题,只是想知道到底发生了什么。

为什么 TypeScript 对这些片段 1 和 2 的处理方式不同?


对于因为同样的错误而发现这个问题的用户,解决它的方法是更严格地输入展开的参数:

foo(1, ...[2] as const);
foo(1, ...[2] as [number]);
foo(1, 2, ...[] as const);
foo(1, 2, ...[] as []);

这是一个 minimal example 没有任何“不应该是一个元组”的方面:

declare const arr: number[];
function foo(a: number, b: number) {/* ... */ }

foo(...arr); // expected 2, got 0 or more
foo(1, ...arr); // expected 2, got 1 or more
foo(1, 2, ...arr) // expected 2, got *3* or more ?!
foo(1, 2, 3, ...arr) // expected 2, got *4* or more ?!

这些都是错误;在前两种情况下,编译器 必须 错误,因为可能无法使用足够的参数调用函数。

在最后两种情况下,人们可能会争辩说不应该有错误,因为使用比需要更多的参数调用函数通常是安全的(请参阅 the TypeScript FAQ 以了解此原则应用于函数类型的可分配性), 但编译器无论如何都会在此处产生错误。

不过,您并不是在问“为什么会出现 错误”。您在问“为什么会出现 that 错误”?毕竟,按理说,问题是 foo(1, 2, ...arr) 正在传递 2 个或更多参数,而编译器正在执行 exactly 2。那么为什么编译器说你正在传递“3 or more”而不是“2 or more”?

根据 microsoft/TypeScript#20071 的说法,这似乎是一个有意的决定,为过度传播参数引入错误的拉取请求:

This PR also changes the error for excess spread arguments to be more understandable:

"Expected 3 arguments, but got least 4".

Previously the error would have been "Expected 3 arguments, but got at least 3", which is, again, technically correct, but not understandable.

我想看到“预期 2,但至少得到 2”的用户会感到困惑,因为“至少 2”显然与“2”兼容。相反,他们决定写出一条消息,如果不是准确的话,那肯定是错误情况。这是官方的回答。

你可以在 these lines 中看到,给定一个像 (a1, a2, a3, ...spreadArg) 这样的参数列表,如果你有足够的参数而没有它,传播参数也会被计算在内;否则不是。因此,如果它需要 2 个参数,则 (1, ...arr) 被计为 1 个参数,但 (1, 2, ...arr) 被计为 3.


坦率地说,在研究了这个之后我对此并不太高兴,因为我可以想象错误信息是正确的但不太清楚(在我看来):

foo(...arr); // expected exactly 2 arguments, but maybe got too few or too many
foo(1, ...arr); // expected exactly 2 arguments, but maybe got too few or too many 
foo(1, 2, ...arr); // expected exactly 2 arguments, but maybe got too many
foo(1, 2, 3, ...arr); // expected exactly 2 arguments, but got too many

这已经在 microsoft/TypeScript#20097 (closed as "working as intended") and in microsoft/TypeScript#20372 中报道过(打开为“需要帮助”),所以如果你很关心它,你(或任何读到这篇文章的人)可以给其中一个甚至提交修复它的拉取请求。


好的,希望对你有帮助;祝你好运!

Playground link fwiw