Repository: TypeScript
Issue: Class field initialization order different between target ES2021 and ES2022
Labels: Suggestion,Help Wanted,Experience Enhancement

# Bug Report

<!--
  Please fill in each section completely. Thank you!
-->

### 🔎 Search Terms

<!--
  What search terms did you use when trying to find an existing bug report?
  List them here so people in the future can find this one more easily.
-->
ES2022 class field initialization order

### 🕗 Version & Regression Information

<!-- When did you start seeing this bug occur?

"Bugs" that have existed in TS for a long time are very likely to be FAQs; refer to
  https://github.com/Microsoft/TypeScript/wiki/FAQ#common-bugs-that-arent-bugs

If possible, please try testing the nightly version of TS to see if it's already been fixed.
For npm: `typescript@next`
This is also the 'Nightly' version in the playground: http://www.typescriptlang.org/play/?ts=Nightly

Note: The TypeScript Playground can be used to try older versions of TypeScript.

Please keep and fill in the line that best applies:
-->
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about _________

### ⏯ Playground Link

<!--
  A link to a TypeScript Playground "Share" link which shows this behavior

  The TypeScript Workbench can be used for more complex setups, try
  https://www.typescriptlang.org/dev/bug-workbench/

  As a last resort, you can link to a repo, but these will be slower for us to investigate.
-->
[Playground link with relevant code](https://www.typescriptlang.org/play?target=9#code/JYOwLgpgTgZghgYwgAgApynAtsg3gKGWTgC5kQBXLAI2gG58BfffBAGzgGdPkAVCTmDyFkAelHIEAexCCoFBGClRkYABZwhnCGB5xkMYBDYATEdNlh5i5QAoADlGAA3TSnsZsZdJiwBKAiJmEXFkCm1VDSFDYxNVKWRtITgQKXVoAyNTEX0AXkjgTgA6D18iuAZgi0FVZHyQCAB3PgEwW1xSZABGAAZGPwZqqTYIIrYpAHNbMHKB-CA)

### 💻 Code

<!-- Please post the relevant code sample here as well-->
```ts
interface Param {
  a: number;
}

class Test {
  // constructor that sets a field
  constructor(private param: Param){
  }

  // use that field to set another field
  a = this.param.a;
}

const t = new Test({a: 10});
console.log(t.a);
```

### 🙁 Actual behavior

<!-- What happened, and why it was wrong -->
If the compiler is set to target "ES2021" then the output will be:

```ts
"use strict";
class Test {
    constructor(param) {
        this.param = param;
        this.a = this.param.a;
    }
}
const t = new Test({ a: 10 });
console.log(t.a);
```

If the target is set to "ES2022" then the output will be:

```ts
"use strict";
class Test {
    param;
    constructor(param) {
        this.param = param;
    }
    a = this.param.a;
}
const t = new Test({ a: 10 });
console.log(t.a);
```

These look logically the same, just utilizing the field syntax in Javascript, but in Javascript fields are initialized BEFORE the constructor is run.

So that means that ES2021 will work, setting the `param` field on `Test` and then use it to set the `a` field, but with ES2022 it will attempt to set `a` first, using the `param` field which has not been initialized yet, thus throwing an error at runtime.

There is no warning or error that this will happen, and I could not find any kind of compiler flag to enable such an error. Even "strictPropertyInitialization" didn't catch this like I thought it might.

### 🙂 Expected behavior

<!-- What you expected to happen instead, and why -->

In order to maintain Javascript semantics, I believe that Typescript should not allow field initializers to access these automatic field setting constructor parameters. Typescript should not allow you to do something that will simply not work.

Alternatively, the compiler could be changed to insert the initializer at the end of the constructor. This would maintain existing Typescript behavior at the expense of being different from Javascript.