Konrad
Konrad

Reputation: 4802

Typescript target warnings after Angular 15 update

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?

Upvotes: 37

Views: 42768

Answers (4)

Roland
Roland

Reputation: 1

If modifying tsconfig.json wasn't enough, this worked for me: There were multiple ts config files (e.g. tscofig.base.json) where i have to set the target to ES2022. (I used search on 'target' to find all of them in the project) - angular 18

Upvotes: 0

JSON Derulo
JSON Derulo

Reputation: 17688

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.

Upvotes: 44

Simon_Weaver
Simon_Weaver

Reputation: 146120

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

Upvotes: 12

user1203108
user1203108

Reputation: 391

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.

Upvotes: 24

Related Questions