Description
es7 proposal : https://github.com/sebmarkbage/ecmascript-rest-spread
Spread properties
Typing
In my opinion the goal of this method is to be able to duplicate an object and changing some props, so I think it's particularly important in this case to not check duplicate property declaration :
var obj = { x: 1, y: 2};
var obj1 = {...obj, z: 3, y: 4}; // not an error
I have a very naive type check algorithm for a similar feature (JSXSpreadAttribute
) in my little jsx-typescript
fork: I just copy the properties of the spread object in the properties table when I encounter a spread object, and override those property if I encounter a declaration with a similar name.
Emitting
jstransform use Object.assign
, babel introduce a shim:
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
We could either force the presence of assign
function on ObjectConstructor
interface, or provide a similar function (with a different name).
I think that the optimal solution would be to not emit any helper in es6
target (or if Object.assign
is defined), and to emit an helper function for es5
, es3
.
var obj = { x: 1, y: 2};
var obj1 = {...obj, z: 3};
/// ES6 emit
var obj = {x: 1, y: 2};
var obj1= Object.assign({}, obj, { z: 3 });
//ES3 emit
var __assign = function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
var obj = {x: 1, y: 2};
var obj1= __assign({}, obj, { z: 3 });
Rest properties
Typing
For simple object the new type is a subtype of the assignation that does not contains properties that has been captured before the rest properties :
var obj = {x:1, y: 1, z: 1};
var {z, ...obj1} = obj;
obj1// {x: number; y:number};
If the destructuring assignment has an index declaration, the result has also a similar index declaration:
var obj: { [string: string]: string };
var {[excludedId], ...obj1} = obj;
obj1// { [string: string]: string };
new/call declarations are obviously not captured:
var obj: { (): void; property: string};
var { ...obj1} = obj;
obj1// { property: string };
Emitting
It is not possible to emit rest properties without an helper function, this one is from babel:
var obj = {x:1, y: 1, z: 1};
var {z, ...obj1} = obj;
var __objectWithoutProperties = function(obj, keys) {
var target = {};
for (var i in obj) {
if (keys.indexOf(i) >= 0) continue;
if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
target[i] = obj[i];
}
return target;
};
var obj = {x:1, y: 1, z: 1};
var z = obj.z;
var obj1 = __objectWithoutProperties(obj, ["z"]);
Edit: added some little typing/emitting example