angulartypescriptangular-aot

Typescript map in angular with AOT


I am using typescript map (testMap: Map<string, Array<string>> = new Map<string, Array<string>>();) in my angular application and everything works if I run it using 'ng serve'. But if run it using 'ng serve --aot', maps are not working. I don't get any exception but the maps are null when I debug my code. I want to know if it's a known issue and if there is a workaround for this. Thank you for your help.

//myLibrary

export class MyModule {
   static forRoot(config: MyConfig ): ModuleWithProviders {
    return {
      ngModule: MyModule,
      providers: [
          {provide: MY_CONFIG, useValue: config} 
      ]
    }
  }

}


export class MyConfig {
    myArray? :  string[];
    myMap?: Map<string, string[]>;

}

//user application

export const testMap: Map<string, string[]> = new Map<string, string[]>();
testMap.set("key1", ["value1", "value2"]);
testMap.set("key2", ["value3", "value4"]);


@NgModule({
  declarations: [
// some code
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    HttpClientModule,
    MyModule.forRoot({
        myArray: ["1234"],
        myMap: testMap,
      }
    ),
  ],
  providers: [
  ],
  bootstrap: [AppComponent]
})
export class AppModule {

}

Solution

  • The problem is that you cannot use anything that is not statically analyzable inside @NgModule if you want to build it with --aot
    So you cannot call functions neither inside @NgModule nor in static forRoot method.
    In order to create a Map it is necessary to call some functions (e.g. ctor, set).
    You can replace Map with ordinary arrays and it will work.
    Later on Map can be constructed from an array like this:

    //...
    export class MyConfig {
        myArray? :  string[];
        myMap?: [string, string[]][];
    
    }
    //...
    export const testMap = [['test1', ['test1', 'test2']]]
    //...
    // setting up imports
    MyModule.forRoot({
        myArray: ["1234"],
        myMap: testMap,
      }
    ),
    //...
    // config usage in your library
    @Injectable()
    export SomeService {
      private readonly myMap: Map<string, string[]>;
      constructor(@Inject(MY_CONFIG) config: MyConfig) {
        // converting from array to map
        this.myMap = new Map(config.myMap);
      }
    }