TypeScript decorators: decorators on class properties don't get transpiled
Created by: metawave
When using class properties decorators, the compiler doesn't generate the nessecary Object.defineProperty calls to make real properties, making the use of mobx or libraries which depend on decorators useless.
Steps to reproduce:
- use latest create-react-app (im my case 2.1.1) to create a new project with typescript support:
npx create-react-app myproject --typescript
- Add mobx, mobx-react to the project
yarn add mobx mobx-react
- Create a model class with
@observable
properties - Decorate a React component with the
@observer
decorator and add the Model class as an instance to this component's props and use it in the render() method
Expected: The observer get's notified, when property on the model has changed and therefore re-rendered
Actual: The observer doesn't get notified
What went wrong: The decorators on properties of the class don't get generated as javascript, therefore the changed notification doesn't get fired and the observer doesn't get it.
Reason: The reason is that in transpilation to javascript the decorators on class propeties/fields don't get generated.
var State = function State() {
Object(_Users_marcel_Source_test2_node_modules_babel_runtime_helpers_esm_classCallCheck__WEBPACK_IMPORTED_MODULE_0__["default"])(this, State);
this.text = '';
};
instead of
var _class, _descriptor;
var State = (_class = function State() {
Object(_Users_marcel_Source_test2_node_modules_babel_runtime_helpers_esm_classCallCheck__WEBPACK_IMPORTED_MODULE_1__["default"])(this, State);
Object(_Users_marcel_Source_test2_node_modules_babel_runtime_helpers_esm_initializerDefineProperty__WEBPACK_IMPORTED_MODULE_0__["default"])(this, "text", _descriptor, this);
this.text = '';
}, (_descriptor = Object(_Users_marcel_Source_test2_node_modules_babel_runtime_helpers_esm_applyDecoratedDescriptor__WEBPACK_IMPORTED_MODULE_2__["default"])(_class.prototype, "text", [mobx__WEBPACK_IMPORTED_MODULE_4__["observable"]], {
configurable: true,
enumerable: true,
writable: true,
initializer: null
})), _class);
Steps to make it work:
- add craco to the project
yarn add @craco/craco
- add class properties and decorators babel plugin also to this project
yarn add --dev @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators
- add following craco.config.js to the project:
module.exports = {
babel: {
plugins: [
["@babel/plugin-proposal-decorators", { legacy: true }],
["@babel/plugin-proposal-class-properties", { loose: true }]
]
}
};
- change
react-scripts start
tocraco start
in package.json, scripts.
Now it should work like expected.
Demo Project: I've created a sample really quick and dirty project on github, with both variants, a non-working (on master) and a working (on branch working): https://github.com/metawave/property-decorator-demo/