Bug Report
Description
When a class has a class decorator and a static field initializer that references super, @babel/plugin-proposal-decorators (version 2023-11) incorrectly moves the static field to an instance field in the _identity wrapper class. Because super in the wrapper class resolves to _identity (not the actual parent class), the initializer crashes at runtime.
Versions
@babel/core: 7.29.0
@babel/plugin-proposal-decorators: 7.29.0
version option: "2023-11"
Reproduction
const babel = require("@babel/core");
const code = `
function customElement(tag) {
return (cls, ctx) => { ctx.addInitializer(() => {}); };
}
class Base {
static styles = ["base"];
}
@customElement("derived")
class Derived extends Base {
static styles = [...super.styles, "derived"];
}
console.log(Derived.styles);
`;
const result = babel.transform(code, {
plugins: [["@babel/plugin-proposal-decorators", { version: "2023-11" }]],
});
eval(result.code);
// TypeError: (intermediate value).styles is not iterable
Generated output (simplified)
The plugin generates this pattern for the decorated class:
let _Derived;
new class extends _identity {
static [class Derived extends Base {
static {
[_Derived, _initClass] = _applyDecs(this, [_dec], [], 0, void 0, Base).c;
}
}];
styles = [...super.styles, "derived"]; // ❌ instance field, super = _identity
constructor() {
super(_Derived), _initClass();
}
}();
The static field static styles = [...super.styles, "derived"] is moved to the wrapper class as an instance field styles = [...]. In this new context, super refers to _identity (a helper function), not Base. Since _identity.styles is undefined, the spread throws:
TypeError: (intermediate value).styles is not iterable
Expected behaviour
static styles = [...super.styles, "derived"] should remain a static field on Derived, with super.styles correctly resolving to Base.styles. Expected output:
Workaround
Replacing super.styles with an explicit reference to the parent class avoids the issue:
@customElement("derived")
class Derived extends Base {
static styles = [...Base.styles, "derived"]; // explicit reference works
}
Or using Object.getPrototypeOf(this).styles (since this in a static field initializer is the class itself).
Note: SWC (@swc/core with decoratorVersion: "2023-11") generates the identical wrapper class pattern and exhibits the same bug. Issue filed at swc-project/swc#11780.
Bug Report
Description
When a class has a class decorator and a static field initializer that references
super,@babel/plugin-proposal-decorators(version2023-11) incorrectly moves the static field to an instance field in the_identitywrapper class. Becausesuperin the wrapper class resolves to_identity(not the actual parent class), the initializer crashes at runtime.Versions
@babel/core:7.29.0@babel/plugin-proposal-decorators:7.29.0versionoption:"2023-11"Reproduction
Generated output (simplified)
The plugin generates this pattern for the decorated class:
The static field
static styles = [...super.styles, "derived"]is moved to the wrapper class as an instance fieldstyles = [...]. In this new context,superrefers to_identity(a helper function), notBase. Since_identity.stylesisundefined, the spread throws:Expected behaviour
static styles = [...super.styles, "derived"]should remain a static field onDerived, withsuper.stylescorrectly resolving toBase.styles. Expected output:Workaround
Replacing
super.styleswith an explicit reference to the parent class avoids the issue:Or using
Object.getPrototypeOf(this).styles(sincethisin a static field initializer is the class itself).Note: SWC (
@swc/corewithdecoratorVersion: "2023-11") generates the identical wrapper class pattern and exhibits the same bug. Issue filed at swc-project/swc#11780.