evanw / evanw/esbuild

Private field incorrectly initialized before the super call

Open
#4,087 0 comments 2 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
40.1k
Forks
1.3k
PR merge metrics
No merged PRs in 30d

Description

> Sorry that I had to close the prior issue which had no responses (https://github.com/evanw/esbuild/issues/3939) and open this as this bug is blocking us and our framework users (Serenity) from updating esbuild to 0.24 or later:

This is an issue introduced in 0.24 as 0.23.1 does not have this problem. Probably introduced with the fix to https://github.com/evanw/esbuild/issues/3913

- [ESBuild Playground Link](https://esbuild.github.io/try/#dAAwLjI0LjAAewogIGxvYWRlcjogJ3RzJywKICBmb3JtYXQ6ICdpaWZlJywKICB0YXJnZXQ6ICdlczIwMTUnLAogIHRzY29uZmlnUmF3OiB7CiAgICBjb21waWxlck9wdGlvbnM6IHsKICAgICAgdXNlRGVmaW5lRm9yQ2xhc3NGaWVsZHM6IGZhbHNlCiAgICB9CiAgfSwKfQBmdW5jdGlvbiB0ZXN0RGVjb3JhdG9yKGE6IHN0cmluZykgewogIHJldHVybiBmdW5jdGlvbiAodGFyZ2V0OiBGdW5jdGlvbiwgX2NvbnRleHQ/OiBhbnkpIHsKIH0KfQoKY2xhc3MgQSB7CiAgIGNvbnN0cnVjdG9yKCkgewogICB9Cn0KCkB0ZXN0RGVjb3JhdG9yKCJhIikKY2xhc3MgQiBleHRlbmRzIEEgewogIHByaXZhdGUgbTE6IGFueTsKCiAgY29uc3RydWN0b3IoKSB7CiAgICBzdXBlcigpOwogIH0KCn0KCm5ldyBCKCk7)

```js
{
loader: 'ts',
format: 'iife',
target: 'es2015',
tsconfigRaw: {
compilerOptions: {
useDefineForClassFields: false
}
}
}
```

```typescript
function testDecorator(a: string) {
return function (target: Function, _context?: any) { }
}

class A {
constructor() {
}
}

@testDecorator("a")
class B extends A {
private m1: any;

constructor() {
super();
}

}

new B();
```

The generated constructor for the derived B class with a private field includes a field initializer before the super call which results in the following error in browser console if you copy paste the generated code:

```
VM17:64 Uncaught ReferenceError: Must call super constructor in derived class
before accessing 'this' or returning from derived constructor
at new B (:64:7)
at :71:3
at :72:3
```

```js
class B extends (_a = A) {
constructor() {
this.m1 = void 0;
super();
}
}
```

In addition to producing invalid code, I think this behavior should only be applied to properties with decorators themselves (not when only the class itself has a decorator). Otherwise this will be a breaking change for those using useDefineForClassFields: false.

TypeScript does not do this for classes with only class decorators:

https://www.typescriptlang.org/play/?target=2#code/GYVwdgxgLglg9mABFApgZygERROAnAQynwAooC8BzFKALkQLAE8AaRXMVADzoeYEpEAbwBQAXxEiIAGwJo0iAILCRiNRwx4Q0UoNFrEEiSIACqDNlyFieKbPmIAQohQ8UYACYLl+xAFsARnpGJgBuSXUETW0bEj1VAzQQAAcUPDjwtWNjMBQAdycMoA

But only for individual properties with decorators:

https://www.typescriptlang.org/play/?target=2#code/GYVwdgxgLglg9mABFApgZygERROAnAQynwAooC8BzFKALkQLAE8AaRXMVADzoeYEpEAbwBQAXxEiIAGwJo0iAILCRiNRwx4Q0UoNFrEEiVNnzEAIUQoeKMABMFy-YgACqDNlyFieVYgAOeDAAbkQoiAC2AIz0jEwA3JLqCJraPiR6fmpoIP4oeBmJasbGYCgA7haFQA

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the linked esbuild Playground reproduction and compare the generated output between 0.23.1 and 0.24 or later. Investigate the TypeScript class-field and decorator transformation for a derived class, then verify that the generated constructor calls super before initializing the private field and matches the stated decorator behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, javascript, typescript
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.