diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts index a19261665d..54cb3a65cb 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts @@ -197,9 +197,20 @@ export class NgModuleDecoratorHandler implements DecoratorHandler` + * @param type The type to reflect on. + * @returns the identifier of the NgModule type if found, or null otherwise. + */ + private _reflectModuleFromTypeParam(type: ts.TypeNode): ts.Expression|null { // Examine the type of the function to see if it's a ModuleWithProviders reference. - if (type === undefined || !ts.isTypeReferenceNode(type) || !ts.isIdentifier(type.typeName)) { + if (!ts.isTypeReferenceNode(type) || !ts.isIdentifier(type.typeName)) { return null; } @@ -226,6 +237,32 @@ export class NgModuleDecoratorHandler implements DecoratorHandler { }); }); + it('should unwrap a ModuleWithProviders-like function if a matching literal type is provided for it', + () => { + env.tsconfig(); + env.write(`test.ts`, ` + import {NgModule} from '@angular/core'; + import {RouterModule} from 'router'; + + @NgModule({imports: [RouterModule.forRoot()]}) + export class TestModule {} + `); + + env.write('node_modules/router/index.d.ts', ` + import {ModuleWithProviders} from '@angular/core'; + + export interface MyType extends ModuleWithProviders {} + + declare class RouterModule { + static forRoot(): (MyType)&{ngModule:RouterModule}; + } + `); + + env.driveMain(); + + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('imports: [[RouterModule.forRoot()]]'); + + const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents).toContain(`import * as i1 from 'router';`); + expect(dtsContents) + .toContain( + 'i0.ɵNgModuleDefWithMeta'); + }); + it('should inject special types according to the metadata', () => { env.tsconfig(); env.write(`test.ts`, `