-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inconsistent parameter properties initialization order depending on the target syntax with useDefineForClassFields #45995
Comments
@nicolo-ribaudo for I think the name I think |
that said, if this can be fixed, even if it's essentially "breaking", even better. |
…MA output With this change we reduce the reliance on the TypeScript target compiler option to output a certain ECMA version. Instead we now use the browsers that are configured in the Browserslist configuration to determine which ECMA features and version are needed. This is done by passing the transpiled TypeScript to Babel preset-env. **Note about useDefineForClassFields**: while setting this to `false` will output JavaScript which is not spec compliant, this is needed because TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the spec have a different runtime behavior to TypeScript’s implementation but the same syntax. Therefore, we opt-out from using upcoming ECMA runtime behavior to better support the ECO system and libraries that depend on the non spec compliant output. One of biggest case is usages of the deprected `@Effect` decorator by NGRX which otherwise would cause runtime failures. Dropping `useDefineForClassFields` will be considered in a future major releases. For more information see: microsoft/TypeScript#45995. BREAKING CHANGE: Internally. the Angular CLI now always set the TypeScript `target` to `ES2022` and `useDefineForClassFields` to `false` unless the target is set to `ES2022` or later in the TypeScript configuration. To control ECMA version and features use the Browerslist configuration.
…MA output With this change we reduce the reliance on the TypeScript target compiler option to output a certain ECMA version. Instead we now use the browsers that are configured in the Browserslist configuration to determine which ECMA features and version are needed. This is done by passing the transpiled TypeScript to Babel preset-env. **Note about useDefineForClassFields**: while setting this to `false` will output JavaScript which is not spec compliant, this is needed because TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the spec have a different runtime behavior to TypeScript’s implementation but the same syntax. Therefore, we opt-out from using upcoming ECMA runtime behavior to better support the ECO system and libraries that depend on the non spec compliant output. One of biggest case is usages of the deprected `@Effect` decorator by NGRX which otherwise would cause runtime failures. Dropping `useDefineForClassFields` will be considered in a future major releases. For more information see: microsoft/TypeScript#45995. BREAKING CHANGE: Internally. the Angular CLI now always set the TypeScript `target` to `ES2022` and `useDefineForClassFields` to `false` unless the target is set to `ES2022` or later in the TypeScript configuration. To control ECMA version and features use the Browerslist configuration.
…MA output With this change we reduce the reliance on the TypeScript target compiler option to output a certain ECMA version. Instead we now use the browsers that are configured in the Browserslist configuration to determine which ECMA features and version are needed. This is done by passing the transpiled TypeScript to Babel preset-env. **Note about useDefineForClassFields**: while setting this to `false` will output JavaScript which is not spec compliant, this is needed because TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the spec have a different runtime behavior to TypeScript’s implementation but the same syntax. Therefore, we opt-out from using upcoming ECMA runtime behavior to better support the ECO system and libraries that depend on the non spec compliant output. One of biggest case is usages of the deprected `@Effect` decorator by NGRX which otherwise would cause runtime failures. Dropping `useDefineForClassFields` will be considered in a future major releases. For more information see: microsoft/TypeScript#45995. BREAKING CHANGE: Internally the Angular CLI now always set the TypeScript `target` to `ES2022` and `useDefineForClassFields` to `false` unless the target is set to `ES2022` or later in the TypeScript configuration. To control ECMA version and features use the Browerslist configuration.
…MA output With this change we reduce the reliance on the TypeScript target compiler option to output a certain ECMA version. Instead we now use the browsers that are configured in the Browserslist configuration to determine which ECMA features and version are needed. This is done by passing the transpiled TypeScript to Babel preset-env. **Note about useDefineForClassFields**: while setting this to `false` will output JavaScript which is not spec compliant, this is needed because TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the spec have a different runtime behavior to TypeScript’s implementation but the same syntax. Therefore, we opt-out from using upcoming ECMA runtime behavior to better support the ECO system and libraries that depend on the non spec compliant output. One of biggest case is usages of the deprected `@Effect` decorator by NGRX which otherwise would cause runtime failures. Dropping `useDefineForClassFields` will be considered in a future major releases. For more information see: microsoft/TypeScript#45995. BREAKING CHANGE: Internally the Angular CLI now always set the TypeScript `target` to `ES2022` and `useDefineForClassFields` to `false` unless the target is set to `ES2022` or later in the TypeScript configuration. To control ECMA version and features use the Browerslist configuration.
…MA output With this change we reduce the reliance on the TypeScript target compiler option to output a certain ECMA version. Instead we now use the browsers that are configured in the Browserslist configuration to determine which ECMA features and version are needed. This is done by passing the transpiled TypeScript to Babel preset-env. **Note about useDefineForClassFields**: while setting this to `false` will output JavaScript which is not spec compliant, this is needed because TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the spec have a different runtime behavior to TypeScript’s implementation but the same syntax. Therefore, we opt-out from using upcoming ECMA runtime behavior to better support the ECO system and libraries that depend on the non spec compliant output. One of biggest case is usages of the deprected `@Effect` decorator by NGRX which otherwise would cause runtime failures. Dropping `useDefineForClassFields` will be considered in a future major releases. For more information see: microsoft/TypeScript#45995. BREAKING CHANGE: Internally the Angular CLI now always set the TypeScript `target` to `ES2022` and `useDefineForClassFields` to `false` unless the target is set to `ES2022` or later in the TypeScript configuration. To control ECMA version and features use the Browerslist configuration.
…MA output With this change we reduce the reliance on the TypeScript target compiler option to output a certain ECMA version. Instead we now use the browsers that are configured in the Browserslist configuration to determine which ECMA features and version are needed. This is done by passing the transpiled TypeScript to Babel preset-env. **Note about useDefineForClassFields**: while setting this to `false` will output JavaScript which is not spec compliant, this is needed because TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the spec have a different runtime behavior to TypeScript’s implementation but the same syntax. Therefore, we opt-out from using upcoming ECMA runtime behavior to better support the ECO system and libraries that depend on the non spec compliant output. One of biggest case is usages of the deprected `@Effect` decorator by NGRX which otherwise would cause runtime failures. Dropping `useDefineForClassFields` will be considered in a future major releases. For more information see: microsoft/TypeScript#45995. BREAKING CHANGE: Internally the Angular CLI now always set the TypeScript `target` to `ES2022` and `useDefineForClassFields` to `false` unless the target is set to `ES2022` or later in the TypeScript configuration. To control ECMA version and features use the Browerslist configuration.
…MA output With this change we reduce the reliance on the TypeScript target compiler option to output a certain ECMA version. Instead we now use the browsers that are configured in the Browserslist configuration to determine which ECMA features and version are needed. This is done by passing the transpiled TypeScript to Babel preset-env. **Note about useDefineForClassFields**: while setting this to `false` will output JavaScript which is not spec compliant, this is needed because TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the spec have a different runtime behavior to TypeScript’s implementation but the same syntax. Therefore, we opt-out from using upcoming ECMA runtime behavior to better support the ECO system and libraries that depend on the non spec compliant output. One of biggest case is usages of the deprected `@Effect` decorator by NGRX which otherwise would cause runtime failures. Dropping `useDefineForClassFields` will be considered in a future major releases. For more information see: microsoft/TypeScript#45995. BREAKING CHANGE: Internally the Angular CLI now always set the TypeScript `target` to `ES2022` and `useDefineForClassFields` to `false` unless the target is set to `ES2022` or later in the TypeScript configuration. To control ECMA version and features use the Browerslist configuration.
…MA output With this change we reduce the reliance on the TypeScript target compiler option to output a certain ECMA version. Instead we now use the browsers that are configured in the Browserslist configuration to determine which ECMA features and version are needed. This is done by passing the transpiled TypeScript to Babel preset-env. **Note about useDefineForClassFields**: while setting this to `false` will output JavaScript which is not spec compliant, this is needed because TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the spec have a different runtime behavior to TypeScript’s implementation but the same syntax. Therefore, we opt-out from using upcoming ECMA runtime behavior to better support the ECO system and libraries that depend on the non spec compliant output. One of biggest case is usages of the deprected `@Effect` decorator by NGRX which otherwise would cause runtime failures. Dropping `useDefineForClassFields` will be considered in a future major releases. For more information see: microsoft/TypeScript#45995. BREAKING CHANGE: Internally the Angular CLI now always set the TypeScript `target` to `ES2022` and `useDefineForClassFields` to `false` unless the target is set to `ES2022` or later in the TypeScript configuration. To control ECMA version and features use the Browerslist configuration.
…MA output With this change we reduce the reliance on the TypeScript target compiler option to output a certain ECMA version. Instead we now use the browsers that are configured in the Browserslist configuration to determine which ECMA features and version are needed. This is done by passing the transpiled TypeScript to Babel preset-env. **Note about useDefineForClassFields**: while setting this to `false` will output JavaScript which is not spec compliant, this is needed because TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the spec have a different runtime behavior to TypeScript’s implementation but the same syntax. Therefore, we opt-out from using upcoming ECMA runtime behavior to better support the ECO system and libraries that depend on the non spec compliant output. One of biggest case is usages of the deprected `@Effect` decorator by NGRX which otherwise would cause runtime failures. Dropping `useDefineForClassFields` will be considered in a future major releases. For more information see: microsoft/TypeScript#45995. BREAKING CHANGE: Internally the Angular CLI now always set the TypeScript `target` to `ES2022` and `useDefineForClassFields` to `false` unless the target is set to `ES2022` or later in the TypeScript configuration. To control ECMA version and features use the Browerslist configuration.
…MA output With this change we reduce the reliance on the TypeScript target compiler option to output a certain ECMA version. Instead we now use the browsers that are configured in the Browserslist configuration to determine which ECMA features and version are needed. This is done by passing the transpiled TypeScript to Babel preset-env. **Note about useDefineForClassFields**: while setting this to `false` will output JavaScript which is not spec compliant, this is needed because TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the spec have a different runtime behavior to TypeScript’s implementation but the same syntax. Therefore, we opt-out from using upcoming ECMA runtime behavior to better support the ECO system and libraries that depend on the non spec compliant output. One of biggest case is usages of the deprecated `@Effect` decorator by NGRX and potentially other existing code as well which otherwise would cause runtime failures. Dropping `useDefineForClassFields` will be considered in a future major releases. For more information see: microsoft/TypeScript#45995. BREAKING CHANGE: Internally the Angular CLI now always set the TypeScript `target` to `ES2022` and `useDefineForClassFields` to `false` unless the target is set to `ES2022` or later in the TypeScript configuration. To control ECMA version and features use the Browerslist configuration.
…MA output With this change we reduce the reliance on the TypeScript target compiler option to output a certain ECMA version. Instead we now use the browsers that are configured in the Browserslist configuration to determine which ECMA features and version are needed. This is done by passing the transpiled TypeScript to Babel preset-env. **Note about useDefineForClassFields**: while setting this to `false` will output JavaScript which is not spec compliant, this is needed because TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the spec have a different runtime behavior to TypeScript’s implementation but the same syntax. Therefore, we opt-out from using upcoming ECMA runtime behavior to better support the ECO system and libraries that depend on the non spec compliant output. One of biggest case is usages of the deprecated `@Effect` decorator by NGRX and potentially other existing code as well which otherwise would cause runtime failures. Dropping `useDefineForClassFields` will be considered in a future major releases. For more information see: microsoft/TypeScript#45995. BREAKING CHANGE: Internally the Angular CLI now always set the TypeScript `target` to `ES2022` and `useDefineForClassFields` to `false` unless the target is set to `ES2022` or later in the TypeScript configuration. To control ECMA version and features use the Browerslist configuration.
…MA output With this change we reduce the reliance on the TypeScript target compiler option to output a certain ECMA version. Instead we now use the browsers that are configured in the Browserslist configuration to determine which ECMA features and version are needed. This is done by passing the transpiled TypeScript to Babel preset-env. **Note about useDefineForClassFields**: while setting this to `false` will output JavaScript which is not spec compliant, this is needed because TypeScript introduced class fields many years before it was ratified in TC39. The latest version of the spec have a different runtime behavior to TypeScript’s implementation but the same syntax. Therefore, we opt-out from using upcoming ECMA runtime behavior to better support the ECO system and libraries that depend on the non spec compliant output. One of biggest case is usages of the deprecated `@Effect` decorator by NGRX and potentially other existing code as well which otherwise would cause runtime failures. Dropping `useDefineForClassFields` will be considered in a future major releases. For more information see: microsoft/TypeScript#45995. BREAKING CHANGE: Internally the Angular CLI now always set the TypeScript `target` to `ES2022` and `useDefineForClassFields` to `false` unless the target is set to `ES2022` or later in the TypeScript configuration. To control ECMA version and features use the Browerslist configuration.
@rbuckton I see that this issue has been added to the 5.1.0 milestone. Is there any update? Asking because we are aligning our behavior with TS in babel/babel#15583. |
We got more issues by users confused about |
It seems that ES2022 causes typescript to change the initialization order of regular properties vs parameter properties (microsoft/TypeScript#45995), so we need to rearrange the initializations to avoid an error. In practice, it might be fine because we have enabled `babel-plugin-transform-class-properties`, which moves the initialization back after the parameter property, but we shoudn't rely on that, and anyway it upsets the linter.
* Bump ES target version to ES2022 I want to be able to use `WeakRef`, and per element-hq/element-web#24913 (comment), I believe this should be safe. * room.ts: Fix initialisation order It seems that ES2022 causes typescript to change the initialization order of regular properties vs parameter properties (microsoft/TypeScript#45995), so we need to rearrange the initializations to avoid an error. In practice, it might be fine because we have enabled `babel-plugin-transform-class-properties`, which moves the initialization back after the parameter property, but we shoudn't rely on that, and anyway it upsets the linter.
* Bump ES target version to ES2022 I want to be able to use `WeakRef`, and per element-hq/element-web#24913 (comment), I believe this should be safe. * room.ts: Fix initialisation order It seems that ES2022 causes typescript to change the initialization order of regular properties vs parameter properties (microsoft/TypeScript#45995), so we need to rearrange the initializations to avoid an error. In practice, it might be fine because we have enabled `babel-plugin-transform-class-properties`, which moves the initialization back after the parameter property, but we shoudn't rely on that, and anyway it upsets the linter.
* Bump ES target version to ES2022 I want to be able to use `WeakRef`, and per element-hq/element-web#24913 (comment), I believe this should be safe. * room.ts: Fix initialisation order It seems that ES2022 causes typescript to change the initialization order of regular properties vs parameter properties (microsoft/TypeScript#45995), so we need to rearrange the initializations to avoid an error. In practice, it might be fine because we have enabled `babel-plugin-transform-class-properties`, which moves the initialization back after the parameter property, but we shoudn't rely on that, and anyway it upsets the linter.
If we were building the feature from scratch based on the current version of ES, then I would expect that field initializers would run before parameter property initializers given that field initializers don't have access to the constructor body: // @target: esnext
// @useDefineForClassFields: true
class C {
x = 1;
constructor(public y: number) {}
}
// becomes
class C {
x = 1;
y;
constructor(y) {
this.y = y;
}
} This order also has the best semantics when combined with native class element decorators as well as the parameter decorators proposal. Unfortunately, prior to // @target: es2015
// @useDefineForClassFields: false
class C {
x = 1;
constructor(public y: number) {}
}
// becomes
class C {
constructor(y) {
this.y = y;
this.x = 1;
}
} Since field initializers are allowed to access // @target: es2015
// @useDefineForClassFields: false
class C {
x = this.y.x;
constructor(public y: { x: number }) {}
}
// becomes
class C {
constructor(y) {
this.y = y;
this.x = this.y.x;
}
} Any change we make to emit will need to be carefully considered for the potential breaks it would introduce. So far, we've opted to leave the emit order distinct between the two cases under the premise that |
Per the design meeting, the current plan would be to add a deprecation for An initial investigation into the impact of this change was performed in #59623, which only looked for the "use-before-initialization" error illustrated by my third example, above. Only one instance of this error was found in the top 1000 projects, which is a hopeful sign. However, that investigation did not look at other possible issues resulting from side effects. |
As an additional data point, I have applied the change in #59623 to a private repo (~500kLOC) which heavily depends on the "old" initialization order (i.e. |
@JoostK @rbuckton this is how it looks like in our project (around 79k statements according to our code coverage report, approx. 340k LOC (excluding tests) + 497k LOC (tests only - approx. 14k test cases)): Starting with a 0-error-compiling project, when setting target: 'es2022' + useDefineForClassFields: true we suddenly get 1336 errors in 538 files: Possible migration pathsLet's explore, what migration would look like for us. I could think of four different solutions. However, any of those is taking a lot of flexibility away and they all have significant drawbacks. It just feels like a big step back regarding JS ergonomics: 1) The Super Class HackThis is maybe the best option for singleton services that are used in a lot of different places because the consumers don't need to be updated: 2) Conversion Into Functions / MethodsThis could be suitable for components and services dedicated to a component. In this case, there will be only few and obvious places that need to be updated: 3) Moving Things Into The ConstructorThis will easily lead to constructor bloat, especially if you would like to continue to have TS to infer the type of private (maybe even public) properties (in this case, you can't delegate it to separate private methods, because then, type inference will not work any more). In the screenshot, admittedly, we don't use type inference, but some people clearly prefer it over explicitly adding types to private properties. 4) Switching To Inject() - Angular specificThis is the easiest migration path for projects that use (the really slow) TestBed for everything, even for testing simple services. It would mean to completeley abandon constructor dependency injection! This is not an alternative for us because of the testing pains and because it would mean to tightly couple our unit tests to Angular's TestBed (and because we would need 60 test shards then instead of 30 because I'd expect overall test runtime to double). |
Bug Report
🔎 Search Terms
properties initialization esnext order initialization fields useDefineForClassFields
🕗 Version & Regression Information
Ref: babel/babel#13779
⏯ Playground Link
Playground link with relevant code (ES2021 target)
Playground link with relevant code (ESNext target)
💻 Code
🙁 Actual behavior
When targeting ES2021
this.amount
is initialized first; when targeting ESNextthis.name
is initialized first.🙂 Expected behavior
They should be consistent.
The text was updated successfully, but these errors were encountered: