Description
Bug Report
π Search Terms
ES2022 class field initialization order
π Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about _________
β― Playground Link
Playground link with relevant code
π» Code
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
If the compiler is set to target "ES2021" then the output will be:
"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:
"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
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.
Activity
whzx5byb commentedon Jan 20, 2023
Related: #50971
RyanCavanaugh commentedon Jan 24, 2023
I don't think we can change the emit here, but giving a correct error under
strictPropertyInitialization
is definitely desirable hereDrops target to es2021 to avoid field init bugs
tmtron commentedon Jun 9, 2023
So I understand that we must change our code when we want to target es2022. Unfortunately we rely on the initialization order in lots of places all over the code-base.
Do you plan to provide some sort of update-script or eslint auto-fix?
fix: class property initialization
kirbysayshi commentedon Mar 29, 2024
I'm not sure if this also falls under
strictPropertyInitialization
or not:This is arguably, to me at least, an example where the
_state
field is not being strictly initialized because it's effectively impossible under ES2022 (!).this.storage
will not be set by the timethis.initialState()
is executed as a field. It's hard to know right now how many instances of code like this is lurking in a codebase!Playground Link
5 remaining items