Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array destructuring inside object

Create a simple array and destructure it inside an (empty) object:

const foo: Array<number> = [1, 2, 3, 4];
const bar: Array<number> = {...foo};

Shouldn't the type check fail here ? bar does not look like an array to me. Editor does not complain at all and treats bar as an array type even though I can easily check at runtime that it's not.

Edit

Reproducing it easily in the TypeScript playground.

like image 250
Adrian Fâciu Avatar asked Mar 21 '17 12:03

Adrian Fâciu


2 Answers

It it looks like a known issue because {...foo} destructuring is compiled into Object.assign({}, foo), and Object.assign() is declared as

assign<T, U>(target: T, source: U): T & U;

so when the second argument is an array, the result is compatible with array type.

Hopefully it will be fixed when better typing for Object.assign is implemented:

I am close to having a PR for spread types, so when those are in, Object.assign will change to have the correct type:

assign(target: T, source: U): { ...T, ...U }

If implemented correctly, spread types should not consider non-enumerable properties such as length, so your code then will give the same error as

const p: Array<number> = {};

// Type '{}' is not assignable to type 'number[]'.
// Property 'length' is missing in type '{}'.
like image 134
artem Avatar answered Oct 02 '22 23:10

artem


Lets have a look at the resulting javascript:

var __assign = (this && this.__assign) || Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
        s = arguments[i];
        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
            t[p] = s[p];
    }
    return t;
};
var foo = [1, 2, 3, 4];
var bar = __assign({}, foo);

So you basically create an object with the same properties as original destructured array - and as typescript is structural typed it will consider new object compatible with Array as it was shallow copied.

On the other hand if you will do:

const foo1: Array<number> = [1, 2, 3, 4];
const bar1: Array<number> = [...foo1];

The result will be as expected new instance of the array.

like image 23
Amid Avatar answered Oct 02 '22 23:10

Amid