Skip to content

[@babel/plugin-proposal-decorators] static field with super reference incorrectly moved to wrapper class instance field (2023-11) #17929

Description

@Lookwe69

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:

["base", "derived"]

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions