I have the following class:
@log
class Example {
constructor(name, age) {
console.log("Example constructor", name, age);
this.name = name;
this.age = age;
}
}
And this @log
decorator when using legacy decorators:
function log(Class) {
return class extends Class {
constructor(...args) {
console.log("log", args);
super(...args);
}
};
}
// .babelrc
// ...
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
// ...
]
// ...
The above setup works well, and the following code:
const example = new Example("Graham", 34);
Outputs:
log (2) ["Graham", 34]
Example constructor Graham 34
Now, how can I achieve the same result when using non-legacy decorators, i.e.:
// .babelrc
// ...
"plugins": [
[
"@babel/plugin-proposal-decorators",
{ "decoratorsBeforeExport": false }
],
// ...
]
// ...
How can I implement @log
so that it works in the same way as with legacy decorators?
function log(...args) {
const [descriptor] = args;
const { kind, elements } = descriptor;
const newElements = elements.concat({
kind: "method",
placement: "prototype",
key: "constructor",
descriptor: {
value: (...args) => {
// I have tried this but it doesn't work...
console.log("log", args);
},
configurable: true,
writable: true,
enumerable: true,
},
});
return {
kind,
elements: newElements,
};
}
I have tried the code above but it didn't work. The problem is that I do not have a reference to the target when using non-legacy decorators. Do you know if there is a way to achieve the same behaviour as with the legacy ones?
Thank you.
I have found the answer, thanks to loganfsmyth on the BabelJS Slack channel.
You have to return an object with a property called finisher
wrapping the class, e.g.:
function log(...args) {
const [descriptor] = args;
const { kind, elements } = descriptor;
return {
kind,
elements,
finisher: (Class) => {
return class extends Class {
constructor(...args) {
console.log("log", args);
super(...args);
}
};
}
};
}
Then this code when using non-legacy decorators:
@log
class Example {
constructor(name, age) {
console.log("Example constructor", name, age);
this.name = name;
this.age = age;
}
}
const example = new Example("Graham", 34);
Outputs:
log (2) ["Graham", 34]
Example constructor Graham 34
As with legacy decorators.
It was difficult to find the answer because this feature of non-legacy decorators is not documented on @babel/plugin-proposal-decorators.