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.
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 '{}'.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With