Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript parsed spread operator in function call problem #28486

Closed
gilbertoalbino opened this issue Nov 11, 2018 · 6 comments
Closed

Typescript parsed spread operator in function call problem #28486

gilbertoalbino opened this issue Nov 11, 2018 · 6 comments
Assignees
Labels
Duplicate An existing issue was already created In Discussion Not yet reached consensus Suggestion An idea for TypeScript

Comments

@gilbertoalbino
Copy link

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.

@mjbvz mjbvz transferred this issue from microsoft/vscode Nov 12, 2018
@mjbvz
Copy link
Contributor

mjbvz commented Nov 12, 2018

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

@weswigham
Copy link
Member

Control flow narrowing of singleton and literal types would about cover it, I think. #16896 specifically mentions what seems to be exactly this.

@weswigham weswigham added Suggestion An idea for TypeScript Duplicate An existing issue was already created In Discussion Not yet reached consensus labels Nov 12, 2018
@gilbertoalbino
Copy link
Author

@mjbvz in plain Javascript, it is valid Javascript, Why wouldn't it be in TypeScript!????

@Nathan-Fenner
Copy link
Contributor

Nathan-Fenner commented Nov 12, 2018

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.

@Nathan-Fenner
Copy link
Contributor

Nathan-Fenner commented Nov 12, 2018

@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.

@gilbertoalbino
Copy link
Author

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created In Discussion Not yet reached consensus Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

4 participants