Typescript: Expected at least x arguments, but got x or more

Created on 20 Oct 2018  Â·  6Comments  Â·  Source: microsoft/TypeScript


TypeScript Version: 3.2.0-dev.20181019 and 3.1.3


Search Terms: function arguments count, spread, rest
Code

function foo(a: number, ...r: number[]): void { };

const a = [1];

foo(...a, 2); // Expected at least 1 arguments, but got 1 or more.
foo(...a, 2, 3); // Expected at least 1 arguments, but got 2 or more.

Expected behavior:
No errors
"at least 1" == "1 or more"

Actual behavior:
"at least 1" != "1 or more"
Non logical type error.

Playground Link: here

Related Issues:

26350

Related Error Spans Experience Enhancement Suggestion

Most helpful comment

It would be possible to “fix” this case (i.e., not issue errors) only because the type of the fixed parameter (number) is the same as the element type of the rest parameters. If it were foo(a: number, ...r: string[]), we currently issue the same error message, but the real issue is not about _how many_ arguments might be passed depending on the length of the spread array, it’s about how the types of arguments will line up with the parameter types depending on the length of the spread array. That problem will always require an error message, and the special case where all the parameters have the same type seems suspiciously unuseful. We suspect that most of the upvotes here come either from an earlier bug where even spreading tuples of known length into parameters was not allowed (if a is initialized to [1] as const, there is no error—but there used to be one), or from the fact that the error message itself is nonsense.

A better error would be placed on the spread element itself, and convey the general idea of “expected a fixed argument, but got a variable-length spread.”

All 6 comments

Well that’s kind of a nasty bug. Seems like the spread operator is tripping it up somehow. Possibly a bad interaction between using a spread at the call site and a rest parameter in the declaration?

Definitely some bugs with interpreting spread, even without using rest in the function:

function bar(a: number, b: number): void { };
function baz(a: number): void { };

const a: number[] = [];

bar(...a, 2); // Correctly interprets getting "1 or more"" arguments 
bar(...a, 2, 3); // Incorrectly interprets getting "3 or more"" arguments > Should be "2 or more""

baz(...a, 2); // Incorrectly interprets getting "2 or more"" arguments > Should be "1 or more""
baz(...a, 2, 3); // Incorrectly interprets getting "3 or more"" arguments > Should be "2 or more""

Playground

Though these don't have a critical impact since they are correct errors, just incorrect error messages, unlike the top bug. Perhaps related though.

Based on #26350 it seems that the underlying issue is that the compiler balks when a spread potentially crosses a formal argument boundary (which will always be the case if it’s not in tail position and the thing being spreaded is anything other than a 1-tuple).

So there's two things here: clarifying the error messages for most cases to explain the error better, and _possibly_ improving how spread handles arrays? The last one seems less likely, but the error message improvements should be uncontentious.

It would be possible to “fix” this case (i.e., not issue errors) only because the type of the fixed parameter (number) is the same as the element type of the rest parameters. If it were foo(a: number, ...r: string[]), we currently issue the same error message, but the real issue is not about _how many_ arguments might be passed depending on the length of the spread array, it’s about how the types of arguments will line up with the parameter types depending on the length of the spread array. That problem will always require an error message, and the special case where all the parameters have the same type seems suspiciously unuseful. We suspect that most of the upvotes here come either from an earlier bug where even spreading tuples of known length into parameters was not allowed (if a is initialized to [1] as const, there is no error—but there used to be one), or from the fact that the error message itself is nonsense.

A better error would be placed on the spread element itself, and convey the general idea of “expected a fixed argument, but got a variable-length spread.”

best workaround solution is to put a dummy argument unfortunately or retype the input ie. lodash merge
merge({}, [...])
though this still is a bug.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

weswigham picture weswigham  Â·  3Comments

siddjain picture siddjain  Â·  3Comments

zhuravlikjb picture zhuravlikjb  Â·  3Comments

jbondc picture jbondc  Â·  3Comments

bgrieder picture bgrieder  Â·  3Comments