Choose one: is this a bug report or feature request? bug report
Input Code
function Dec(target, key, descriptor) {
// do nothing
return descriptor;
}
class Test {
@Dec
a;
}
let t = new Test();
console.log(t.a); // prints 'undefined'
console.log(Object.getOwnPropertyDescriptor(t, 'a')); // writable: false (should be true)
/* prints:
{ value: undefined,
writable: false,
enumerable: true,
configurable: false }
*/
t.a = 2;
console.log(t.a); // prints 'undefined' (should be 2)
Babel/Babylon Configuration (.babelrc, package.json, cli command)
{
"presets": [
["@babel/preset-env", {
"targets": {
"node": "current"
}
}],
"@babel/preset-stage-2"
],
"plugins": [
"@babel/plugin-proposal-decorators",
[
"@babel/plugin-proposal-class-properties",
{ "loose": true }
]
]
}
Expected Behavior
The property a should be writable.
Current Behavior
writable in a's descriptor is set to false.
Possible Solution
Currently Babel transpiles the code with _applyDecoratedDescriptor function declaration as following:
function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) { var desc = {}; Object['ke' + 'ys'](descriptor).forEach(function (key) { desc[key] = descriptor[key]; }); desc.enumerable = !!desc.enumerable; desc.configurable = !!desc.configurable; if ('value' in desc || desc.initializer) { desc.writable = true; } desc = decorators.slice().reverse().reduce(function (desc, decorator) { return decorator(target, property, desc) || desc; }, desc); if (context && desc.initializer !== void 0) { desc.value = desc.initializer ? desc.initializer.call(context) : void 0; desc.initializer = undefined; } if (desc.initializer === void 0) { Object['define' + 'Property'](target, property, desc); desc = null; } return desc; }
which sets desc.writable true in the following condition:
if ('value' in desc || desc.initializer) { desc.writable = true; }
I don't understand this part. Should this be changed somehow?
Context
This behavior occurs only when both of the following conditions are met:
- A decorator is present on the class property.
- No initializer is defined in the class property declaration.
For example, if there's no decorator:
a is writable.
Transpiled code:
function Dec(target, key, descriptor) {
// do nothing
return descriptor;
}
class Test {
constructor() {
this.a = void 0;
}
}
let t = new Test();
console.log(t.a); // prints 'undefined'
console.log(Object.getOwnPropertyDescriptor(t, 'a')); // writable: false (should be true)
t.a = 2;
console.log(t.a); // prints 'undefined' (should be 2)
Also, if I set an initializer:
class Test {
@Dec
a = 1;
}
a is writable.
Transpiled code:
var _class, _descriptor;
function _initializerDefineProperty(target, property, descriptor, context) { if (!descriptor) return; Object.defineProperty(target, property, { enumerable: descriptor.enumerable, configurable: descriptor.configurable, writable: descriptor.writable, value: descriptor.initializer ? descriptor.initializer.call(context) : void 0 }); }
function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) { var desc = {}; Object['ke' + 'ys'](descriptor).forEach(function (key) { desc[key] = descriptor[key]; }); desc.enumerable = !!desc.enumerable; desc.configurable = !!desc.configurable; if ('value' in desc || desc.initializer) { desc.writable = true; } desc = decorators.slice().reverse().reduce(function (desc, decorator) { return decorator(target, property, desc) || desc; }, desc); if (context && desc.initializer !== void 0) { desc.value = desc.initializer ? desc.initializer.call(context) : void 0; desc.initializer = undefined; } if (desc.initializer === void 0) { Object['define' + 'Property'](target, property, desc); desc = null; } return desc; }
function _initializerWarningHelper(descriptor, context) { throw new Error('Decorating class property failed. Please ensure that ' + 'proposal-class-properties is enabled and set to use loose mode. ' + 'To use proposal-class-properties in spec mode with decorators, wait for ' + 'the next major version of decorators in stage 2.'); }
function Dec(target, key, descriptor) {
// do nothing
return descriptor;
}
let Test = (_class = class Test {
constructor() {
_initializerDefineProperty(this, "a", _descriptor, this);
}
}, (_descriptor = _applyDecoratedDescriptor(_class.prototype, "a", [Dec], {
enumerable: true,
initializer: function () {
return 1;
}
})), _class);
let t = new Test();
console.log(t.a); // prints 'undefined'
console.log(Object.getOwnPropertyDescriptor(t, 'a')); // writable: false (should be true)
t.a = 2;
console.log(t.a); // prints 'undefined' (should be 2)
Your Environment
| software |
version(s) |
| Babel |
see below |
| Babylon |
|
| node |
|
| npm |
|
| Operating System |
|
"@babel/cli": "^7.0.0-beta.40",
"@babel/core": "^7.0.0-beta.40",
"@babel/plugin-proposal-class-properties": "^7.0.0-beta.40",
"@babel/plugin-proposal-decorators": "^7.0.0-beta.39",
"@babel/preset-env": "^7.0.0-beta.39",
"@babel/preset-stage-2": "^7.0.0-beta.39"
Choose one: is this a bug report or feature request? bug report
Input Code
Babel/Babylon Configuration (.babelrc, package.json, cli command)
Expected Behavior
The property
ashould bewritable.Current Behavior
writableina's descriptor is set to false.Possible Solution
Currently Babel transpiles the code with
_applyDecoratedDescriptorfunction declaration as following:which sets
desc.writabletrue in the following condition:if ('value' in desc || desc.initializer) { desc.writable = true; }I don't understand this part. Should this be changed somehow?
Context
This behavior occurs only when both of the following conditions are met:
For example, if there's no decorator:
ais writable.Transpiled code:
Also, if I set an initializer:
ais writable.Transpiled code:
Your Environment