tc39 / proposal-object-rest-spread

Rest/Spread Properties for ECMAScript
1.49k stars 85 forks source link

Rationale for ignoring newly defined setters #65

Open lambda-fairy opened 6 years ago

lambda-fairy commented 6 years ago

I noticed the following caveat in Issues.md:

Setters

Properties on object literals are defined as new value on the object. It does not invoke any newly defined setters. This is different than what Object.assign on a recently defined object does.

let record = { x: 1 };
let obj = { set x() { throw new Error(); }, ...record }; // not error
obj.x; // 1

What is the rationale for this? It feels a bit surprising, as it breaks with the mental model of being sugar over Object.assign.

aij commented 6 years ago

It seems consistent to me. It doesn't break with the mental model of being sugar for "all the fields of that other object go here".

Eg: Your above example (assuming you fix the SyntaxError) is equivalent to

let record = { x: 1 };
let obj = { set x(a) { throw new Error(); }, x: record.x }; // not error
obj.x; // 1

It looks like an object literal, and (unsurprisingly?) it behaves like an object literal.

Out of curiosity, what is the rationale for expecting it to be behave like an object assignment?

lambda-fairy commented 6 years ago

I meant that if we had desugared it to a call to Object.assign instead, then it would raise an error:

let x = Object.assign({ set x(a) { throw new Error(); } }, record);

That would be what I imagine the desugaring to look like, given that record may be an arbitrary parameter whose enumerable properties aren't known in advance.

This difference makes it harder to switch between ES5 and ES20xx syntax, as you'd need to keep this (admittedly rare) special case in mind.

Indeed, TypeScript gets this wrong: Microsoft/TypeScript#13668. And it's hinted in that issue (on my phone, can't check yet) that Babel may be wrong as well.

adrianheine commented 5 years ago

bublé has this issue, too.