Typescript: Spreading array into object should not be assignable to array

Created on 2 Dec 2018  路  6Comments  路  Source: microsoft/TypeScript


TypeScript Version: 3.3.0-dev.20181129


Search Terms: spread array object

Code

const x: number[] = [1, 2, 3, 4];
//Oh, look, a typo.
//Really meant [...x]
//But used     {...x}
const y: number[] = { ...x };

//undefined
console.log(y.length);
//Uncaught TypeError: y.indexOf is not a function
console.log(y.indexOf(3));

Expected behavior:

{ ...x } should not be assignable to number[]

Actual behavior:

{ ...x } is assignable to number[] and results in run-time errors.

Playground Link: here


I actually ran into this problem because I was refactoring some code and decided to use arrays instead of objects. However, I missed a few spots. Luckily, I had unit tests to scream at me.

Needs Proposal Suggestion

Most helpful comment

Tracking at #9726

All 6 comments

The main problem is that builtin types are declared as interface in lib.xxx.d.ts. If Array was declared as class instead, instance methods would be removed from the spreaded type.

Unfortunately class declarations of the same name are not able to merge, which makes it impossible to add Array.prototype.includes in lib.es2016.array.include.d.ts.

I think Event might have a similar problem?

Or MouseEvent, at least.

function foo (evt : MouseEvent) {
    const copy = {...evt};
    console.log(copy.x + 1); //undefined + 1 = NaN
}

isn't undefined + 1 = NaN correct ?

The problem is that MouseEvent.x should be a number.

Tracking at #9726

I just ran into this same thing, so created a test code case:

interface IObjectB {
  name: string;
  value: number;
}

interface IObjectA {
  title: string;
  arrayOfThings: IObjectB[];
}

interface IObjectC {
  objectA: IObjectA;
}

const thingThatShouldNotHappen: IObjectC = {
  objectA: {
    arrayOfThings: {
      ...[{ name: "thing", value: 8 }, { name: "otherThing", value: 9 }]
    },
    title: "Test"
  }
};

const thingThatShouldHappen: IObjectC = {
  objectA: {
    arrayOfThings: [
      ...[{ name: "thing", value: 8 }, { name: "otherThing", value: 9 }]
    ],
    title: "Test"
  }
};

console.log(thingThatShouldHappen);
console.log(thingThatShouldNotHappen);

I should get a compile warning on the thingThatShouldNotHappen; I don't. TS 3.5.3

Was this page helpful?
0 / 5 - 0 ratings