Skip to content

Typescript parsed spread operator in function call problem #28486

Closed
@gilbertoalbino

Description

@gilbertoalbino

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.

Activity

transferred this issue frommicrosoft/vscodeon Nov 12, 2018
mjbvz

mjbvz commented on Nov 12, 2018

@mjbvz
Contributor

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

weswigham commented on Nov 12, 2018

@weswigham
Member

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

gilbertoalbino

gilbertoalbino commented on Nov 12, 2018

@gilbertoalbino
Author

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

Nathan-Fenner

Nathan-Fenner commented on Nov 12, 2018

@Nathan-Fenner
Contributor

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

Nathan-Fenner commented on Nov 12, 2018

@Nathan-Fenner
Contributor

@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

gilbertoalbino commented on Nov 13, 2018

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

Metadata

Metadata

Assignees

Labels

DuplicateAn existing issue was already createdIn DiscussionNot yet reached consensusSuggestionAn idea for TypeScript

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @gilbertoalbino@weswigham@Nathan-Fenner@mjbvz

      Issue actions

        Typescript parsed spread operator in function call problem · Issue #28486 · microsoft/TypeScript