I have a piece of code as is:
function add(a: number, b: number, c: number) {
return a + b + c;
}
const hexagons = [1, 6, 15];
const result = add(...hexagons);
And VS Code complains about:
[ts] Expected 3 arguments, but got 0 or more.
I haven't found if it is necessary to set some config option or this is a bug in the VSCode TS parser itself.
But it is valid code in Chrome:
function add(a, b, c) {
return a + b + c;
}
const hexagons = [1, 6, 15];
const result = add(...hexagons);
So I think VSCode is wrongly parsing TS.
Doing this with array types in general is not valid typescript because you can easily have:
function add(a: number, b: number, c: number) {
return a + b + c;
}
const hexagons = [1, 6, 15];
hexagons.pop();
const result = add(...hexagons);
Not sure if there are existing TS feature requests that would allow this to be supported
Control flow narrowing of singleton and literal types would about cover it, I think. #16896 specifically mentions what seems to be exactly this.
@mjbvz in plain Javascript, it is valid Javascript, Why wouldn't it be in TypeScript!????
Unfortunately, there are a few issues which make extending #16896 soundly extend to TypeScript beyond string/number literals (that is, making it apply to objects/arrays).
When a narrowed value is assigned to, the value gets widened as appropriate, so that the following program behaves as expected:
let x = "foo";
if (x !== "foo") {
throw new Error("narrow x");
}
x; // type: "foo"
x = someString();
x; // type: string
The problem is that today, the following piece of code is also valid:
function pop(xs: number[]) {
xs.pop();
}
const x: [number, number, number] = [1, 2, 3];
push(x);
x; // type: [number, number, number], which is unsound
This is a problem for soundness even ignoring the auto-narrowing condition. But because right now the only way to get fixed-sized tuple types is to explicitly give type annotations, this is not a wide-spread problem.
But automatically narrowing would make fixed-size tuple types much more common (every single array literal!). So you'd potentially end up with arrays that are definitely-a-particular-size all over almost every code base, except that they're totally not.
@gilbertoalbino The actual problem with your code is that hexagons has the inferred type number[]. So ...hexagons could be 0, 1, 2, 3, ... arguments, even though you must pass 3.
@mjbvz 's point is that because you could have removed an item from it (since it's a number[]), it's not sound to permit you to spread it onto your function (or you'd pass an undefined where a number was expected).
Today, you can fix this just by adding a type annotation
function add(a: number, b: number, c: number) {
return a + b + c;
}
const hexagons: [number, number, number] = [1, 6, 15];
const result = add(...hexagons);
If you're going to be using this type frequently, I recommend a type definition:
type Triplet = [number, number, number]
const hexagons: Triplet = [1, 6, 15];
It will probably be a while before a complete auto-narrowing solution can be made for object types.
@Nathan-Fenner indeed using type annotation goes away with the error :
[ts] Expected 3 arguments, but got 0 or more.
But I think I haven't understood yet why this parse error is being triggered.
Most helpful comment
@gilbertoalbino The actual problem with your code is that
hexagonshas the inferred typenumber[]. So...hexagonscould be 0, 1, 2, 3, ... arguments, even though you must pass 3.@mjbvz 's point is that because you could have removed an item from it (since it's a
number[]), it's not sound to permit you to spread it onto your function (or you'd pass anundefinedwhere anumberwas expected).Today, you can fix this just by adding a type annotation
If you're going to be using this type frequently, I recommend a type definition:
It will probably be a while before a complete auto-narrowing solution can be made for object types.