angularangular-clidecoratortsconfiges2022

ClassDecorator with Angular (15) targeting ES2022


We currently are in march 2023 and I am looking for a way to make my class decorators work the right way, with no warning from the cli.

Here my simple code :

function MyDecorator(myConstructor: new (...args: any[]) => any): new (...args: any[]) => any {
  alert('MyDecorator EVALUATE'); // -------------> Alert A
  return class extends myConstructor {
    constructor(...args) {
      super(...args);
      alert('MyDecorator CONSTRUCTOR'); // ------------> Alert B
    }
  };
}

@MyDecorator
@Component({
  // ...
})
export class AppComponent() {
  // ...
} 

Before Angular 15:

I was targeting ES2021 or lower and this worked perfectly. I got alerts A & B and the cli gave no warning.

With Angular 15:

I was still targeting ES2021 and it was still working. I got alerts A & B

BUT the cli warned me it overrided some settings.

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

I tried to set these two settings in the tsconfig.json

    "target": "ES2022",
    "useDefineForClassFields": false,

Then I had no more cli warning BUT I only got the alert A and my decorator implementation is clearly ignored (no alert B was displayed).

It looks like that the "useDefineForClassFields": false is ignored (cf : https://github.com/angular/angular/issues/48276#issuecomment-1362787912)

Well my 2 questions are :

Thanks in advance for any help/explanation ...


Solution

  • "is there a way to make decorators work "natively" in Angular 15/ES2022 ? "

    It appears that there is no intention of supporting custom decorators applied to angular components from Angular 15 onwards:

    https://github.com/angular/angular/issues/48276#issuecomment-1332611012

    Angular doesn't support custom decorators on its component classes or other decorated members. Depending on what the decorator does, it may or may not function correctly.

    We don't support them because there's a big conceptual mismatch - the Angular compiler is trying to statically transform classes according to their Angular annotations, but custom decorators are attempting to arbitrarily change the shape of that class at runtime.


    "if not, is there a way to properly set the useDefineForClassFields compilerOption to avoid the warning of the cli ?"

    I believe you are getting this warning because it is expecting the default value to be used for useDefineForClassFields when targeting ES2022.

    https://angular.schule/blog/2022-11-use-define-for-class-fields

    [When] the target of TypeScript is set to ES2022, the default value for this option is true.

    What does this flag actually do ?

    This means that the native implementation of JavaScript will be used and that the properties will behave in a different way than before. Depending on the setting, the following code has two different outputs:

    class User {
     age = this.currentYear - 1998;
    
     constructor(private currentYear: number) {
       // useDefineForClassFields: false --> Current age: 25
       // useDefineForClassFields: true --> Current age: NaN
       console.log('Current age:', this.age);
     }
    }
    
    const user = new User(2023);