Skip to content

[Bug]: Incorrect transpilation of class name references in static contexts #15696

@evanw

Description

@evanw

💻

  • Would you like to work on a fix?

How are you using Babel?

Programmatic API (babel.transform, babel.parse)

Input code

class Foo {
  static { console.log(this, Foo) }
  static x = () => { console.log(this, Foo) }
}
const oldFoo = Foo;
Foo = null;
oldFoo.x();

Configuration file name

No response

Configuration

(I put the input code into the Babel REPL)

Current and expected behavior

Current behavior: When the output code Babel generates is run, it prints something like this:

Foo Foo
null null

When the input code is run natively, it prints something like this:

Foo Foo
Foo Foo

I expected the behavior of the output code Babel generates to match behavior of the input code.

Environment

(I put the input code into the Babel REPL)

Possible solution

Class declarations in JavaScript generate an outer binding name, which turns out to be mutable (and can be reassigned). Separately, JavaScript also generates an immutable inner binding name that is only in scope within the class body. Referencing the class name within the class body gives the inner immutable binding name, and referencing the class name outside the class body gives the mutable outer binding name.

Currently Babel generates this output code:

var Foo = /*#__PURE__*/_createClass(function Foo() {
  _classCallCheck(this, Foo);
});
console.log(Foo, Foo);
_defineProperty(Foo, "x", function () {
  console.log(Foo, Foo);
});
var oldFoo = Foo;
Foo = null;
oldFoo.x();

This problem could be fixed by generating the following output code instead:

var Foo = /*#__PURE__*/_createClass(function Foo() {
  _classCallCheck(this, Foo);
});
var _Foo = Foo;
console.log(_Foo, _Foo);
_defineProperty(_Foo, "x", function () {
  console.log(_Foo, _Foo);
});
var oldFoo = Foo;
Foo = null;
oldFoo.x();

The modified code explicitly materializes the immutable inner binding name for the code that had to be moved outside of the class body due to syntax lowering.

Additional context

I discovered this bug in Babel because I'm trying to figure out how to handle this in esbuild, and as part of that I'm investigating how Babel transpiles code that does this.

Metadata

Metadata

Assignees

Labels

Spec: ClassesoutdatedA closed issue/PR that is archived due to age. Recommended to make a new issue

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions