Typescript target warnings after Angular 15 update
Asked Answered
B

3

32

I updated my angular app to Angular 15. It builds ok - unless some warnings like:

TypeScript compiler options "target" and "useDefineForClassFields" are set to "ES2022" and "false" respectively by the Angular CLI.

My tsconfig.json sets the target to ES6:

{
  ...
  "compilerOptions": {
      "target": "ES6",
      ...
  }
}

The documentation says:

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.

https://github.com/angular/angular-cli/blob/main/CHANGELOG.md

And my .browserslistrc looks the same for month with no changes since the beginning:

last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR

Thus, how can I get rid of this warning?

Beamer answered 8/1, 2023 at 12:31 Comment(1)
For reference here's the PR github.com/angular/angular-cli/pull/23936Cuprite
H
19

I had the same issue and successfully silenced this warning by adding "target": "ES2022" and "useDefineForClassFields": false to my tsconfig. Whether this was a good idea or not will have to await a comment from someone more knowledgeable than me. I worry that this will fail in the same way that yours now has when 2022 becomes 2023 (or whatever comes next). Surely it would be better if it could be left out completely (as I had) if Angular is going to override it anyway. But I may have an incomplete grasp of the issue.

In your case, you should be able to do (or at least attempt) the same thing in place of ES6 (which I understand to be the same as ES2015). According to the documentation you cited, this is what Angular is doing anyway, regardless of your request, so if you only get the warning and no errors your code should be fine. If you need to restrict things further to the ES6 level, it seems you need to use your .broswerslistrc file to do this, which may also be fine already.

I think the problem here is that the warning is not helpful, at least to people like you and me, who are the ones receiving it and not knowing what to do about it. Also the weblink that follows it ("To control ECMA version and features use the Browerslist configuration. For more information, see https://angular.io/guide/build#configuring-browser-compatibility ") doesn't seem particularly helpful in addressing the warning, telling us what we should be doing but not what to do to get rid of the warning.

Hargis answered 8/1, 2023 at 13:22 Comment(1)
Angular uses Babel to ensure backwards compability with browsers defined in .browserslistrc. So it is safe to use modern tsconfig targets, polyfills for missing features will be added by Babel. For more details, see my answer.Benefactress
B
40

To understand this warning, we first need to understand how the Angular build works.

First, the TypeScript build needs to run. During this step, with the settings in the tsconfig.json, your TypeScript code is being compiled into JavaScript. If you set target to ES6, prior to Angular 15 the TypeScript build would produce ES6 code.

Afterwards, Angular uses Babel to make the generated JavaScript code backwards compatible to older browser versions, see the docs. It goes through the browserslist configuration to get the list of browsers which you wish to support, and will make sure that the application doesn't use a feature which isn't implemented by all supported browsers yet.

Back in the days when Angular supported IE11, this was a lot more complicated. At one point the Angular CLI even generated an extra bundle just for IE11, this was called differential loading. But now that Angular dropped support for IE11, they can simplify things again and move toward modern bundles, which is probably the reason for their changes in v15.

So in my point of view, there is no good reason to set the target in your tsconfig.json to such an old verison like ES6. The modern browsers support way more EcmaScript features now, and using a more up to date EcmaScript version will make your bundle size smaller. Babel will polyfill missing features anyways, so you don't have to worry. Just set the target to ES2022 like they suggest.

Benefactress answered 12/1, 2023 at 8:17 Comment(6)
Do you know any examples how a project compiled with ES2020 vs ES2022 would end up different? Are the babel polyfills more about patching the browser API and the TS compilation would have to rewrite things differently?Cuprite
Until Angular 15 I’ve been using ES6 target so that ?? or ?. can be rewritten for Safari 13.3 compatibility. I’ve ok now to give up on that but I’m not necessarily comfortable jumping to ES2022 if that means I might break some Safari 14 (or whichever version) users.Cuprite
@Cuprite babel doesn't have any effect on the TypeScript compilation. It should polyfill missing browser APIs and features as well, including nullish coalescing, just configure your browserslist accordingly. Besides, Angular only supports the 2 most recent major versions of Safari. We are already on Safari 16, so 13 and 14 are out of support anyways.Benefactress
thanks but there's a difference between 'officially' supporting 14 and being able to support 14 by means of using a lower target (or more lenient browsers file). Which is exactly what I was doing until yesterday to support ?? and ?. in older Safari - we still make money from Safari 13 and 14 people! It's just hard navigating the exact impact of each option in an application but I personally don't see myself using ES2022 for a while.Cuprite
Up-voted your answer as it was well-written and went deeper. I just moved to Angular15 so this IE support issue was a complete mystery to me. It is difficult working with Angular as they keep moving the goal post every few months. I think this framework may fade into posterity in the next decade because of the inability to help developers stuck with older versions. That is a very poor architecture & application design model. I am using Microsoft Blazor instead now, which is much simpler and easier to use and uses a true Object Oriented Language.Landonlandor
@JSONDerulo This was very helpful for me. I am debugging an issue on TV browsers (samsung and andriod tv) and the problem was that it was using operators like ??= in the code which most browsers don't accept. So I had to export browserlist and set it to last 4 Safari major versions to get rid of ??=. However, this is not a perm solution because when we go to Safari 17, then I need to update it to last 5 versions of Safari. Is there a way to force Babel to export to es2020 so I don't have to use browserlist?Wedekind
H
19

I had the same issue and successfully silenced this warning by adding "target": "ES2022" and "useDefineForClassFields": false to my tsconfig. Whether this was a good idea or not will have to await a comment from someone more knowledgeable than me. I worry that this will fail in the same way that yours now has when 2022 becomes 2023 (or whatever comes next). Surely it would be better if it could be left out completely (as I had) if Angular is going to override it anyway. But I may have an incomplete grasp of the issue.

In your case, you should be able to do (or at least attempt) the same thing in place of ES6 (which I understand to be the same as ES2015). According to the documentation you cited, this is what Angular is doing anyway, regardless of your request, so if you only get the warning and no errors your code should be fine. If you need to restrict things further to the ES6 level, it seems you need to use your .broswerslistrc file to do this, which may also be fine already.

I think the problem here is that the warning is not helpful, at least to people like you and me, who are the ones receiving it and not knowing what to do about it. Also the weblink that follows it ("To control ECMA version and features use the Browerslist configuration. For more information, see https://angular.io/guide/build#configuring-browser-compatibility ") doesn't seem particularly helpful in addressing the warning, telling us what we should be doing but not what to do to get rid of the warning.

Hargis answered 8/1, 2023 at 13:22 Comment(1)
Angular uses Babel to ensure backwards compability with browsers defined in .browserslistrc. So it is safe to use modern tsconfig targets, polyfills for missing features will be added by Babel. For more details, see my answer.Benefactress
C
11

Edit: Turns out there was a bug related to this warning, fixed in Angular CLI 16.0.4. For Angular CLI 15 - 16.0.3 make sure you set target="ES2022" to avoid the mismatch described below. Check your CLI version with ng version.


Be careful not to misinterpret the warning, and its consequences!

The full message (as of Angular 16) says this:

TypeScript compiler options "target" and "useDefineForClassFields" are set to "ES2022" and "false" respectively by the Angular CLI. To control ECMA version and features use the Browerslist configuration. For more information, see https://angular.io/guide/build#configuring-browser-compatibility NOTE: You can set the "target" to "ES2022" in the project's tsconfig to remove this warning.

One quite reasonable interpretation of this might be:

Angular is IGNORING whatever I put for compilerOptions.target in your tsconfig.json, and is compiling my code as ES2022.

However, that is NOT what is happening!

To confirm, I created a simple ng new project with Angular 16 and updated my target to ES2015:

compilerOptions: {
   "target": "ES2015"
}

I wrote the following lines of code in my AppComponent, using the nullish coalescing operator which is an ES2022 feature.

const cat = null;
const dog = { catName: 'Kim' };

const animal = cat ?? dog;

Looking at the .js compiled code (not the sourcemapped .ts file) running in the browser via ng serve you'll see the following - demonstrating that the ?? has already been transpiled to be compatible with older browsers:

 const animal = cat !== null && cat !== void 0 ? cat : dog;

This of course doesn't happen out-of-the-box with the ES2022 target.

So let's say you really need to support Safari 13.0 (which doesn't support ??) and think that everything is fine.

Wrong again!

Search in the browser for ?? and you'll see numerous places where ?? is used in the vendor.js file. It is NOT being transpiled there and therefore your app won't work on Safari 13.0.

That's where the browserslist comes in, which if configured will transpile the entire application for a certain target.


What the message really means in practice:

Your application code is being compiled for a target older than ES2022, which may lead to a mismatch between your code and vendor code. We recommend setting your target to ES2022 and using exclusively browserslist to control transpilation for older browsers, to ensure all code is transpiled as intended.


Why I am still confused:

The following commit which introduced this feature appears to set the target to ES2022 but it never actually takes effect for application code. Not sure why.

https://github.com/angular/angular-cli/pull/23936/commits/cdac700b93d5593ce92b44b1691941673eaf25b0#diff-2d55449c69797885b38f6b957a1fd03d27beda366a9270293719ec041cf15d0f

Cuprite answered 31/5, 2023 at 1:10 Comment(1)
I think this behavior is not as intended, and I've filed a bug github.com/angular/angular-cli/issues/25290Cuprite

© 2022 - 2024 — McMap. All rights reserved.