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 5544ddeca8..0b9e025873 100644
--- a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts
+++ b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts
@@ -11,7 +11,7 @@ import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
import {Decorator, ReflectionHost} from '../../host';
-import {Reference, ResolvedReference, ResolvedValue, reflectObjectLiteral, staticallyResolve} from '../../metadata';
+import {Reference, ResolvedReference, ResolvedValue, reflectObjectLiteral, staticallyResolve, typeNodeToValueExpr} from '../../metadata';
import {AnalysisOutput, CompileResult, DecoratorHandler} from '../../transform';
import {generateSetClassMetadataCall} from './metadata';
@@ -223,12 +223,7 @@ export class NgModuleDecoratorHandler implements DecoratorHandler
-export {TypeScriptReflectionHost, filterToMembersWithDecorator, findMember, reflectObjectLiteral, reflectTypeEntityToDeclaration} from './src/reflector';
+export {TypeScriptReflectionHost, filterToMembersWithDecorator, findMember, reflectObjectLiteral, reflectTypeEntityToDeclaration, typeNodeToValueExpr} from './src/reflector';
export {AbsoluteReference, EnumValue, ImportMode, Reference, ResolvedReference, ResolvedValue, isDynamicValue, staticallyResolve} from './src/resolver';
diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/reflector.ts b/packages/compiler-cli/src/ngtsc/metadata/src/reflector.ts
index 32b5dcdab5..fffd71f355 100644
--- a/packages/compiler-cli/src/ngtsc/metadata/src/reflector.ts
+++ b/packages/compiler-cli/src/ngtsc/metadata/src/reflector.ts
@@ -436,7 +436,7 @@ function parameterName(name: ts.BindingName): string|null {
}
}
-function typeNodeToValueExpr(node: ts.TypeNode): ts.Expression|null {
+export function typeNodeToValueExpr(node: ts.TypeNode): ts.Expression|null {
if (ts.isTypeReferenceNode(node)) {
return entityNameToValue(node.typeName);
} else {
diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
index 95be43f914..22313073dd 100644
--- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
+++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
@@ -375,9 +375,10 @@ describe('ngtsc behavioral tests', () => {
'i0.ɵNgModuleDefWithMeta');
});
- it('should unwrap a ModuleWithProviders function if a generic type is provided for it', () => {
- env.tsconfig();
- env.write(`test.ts`, `
+ describe('unwrapping ModuleWithProviders functions', () => {
+ it('should extract the generic type and include it in the module\'s declaration', () => {
+ env.tsconfig();
+ env.write(`test.ts`, `
import {NgModule} from '@angular/core';
import {RouterModule} from 'router';
@@ -385,7 +386,7 @@ describe('ngtsc behavioral tests', () => {
export class TestModule {}
`);
- env.write('node_modules/router/index.d.ts', `
+ env.write('node_modules/router/index.d.ts', `
import {ModuleWithProviders} from '@angular/core';
declare class RouterModule {
@@ -393,15 +394,51 @@ describe('ngtsc behavioral tests', () => {
}
`);
- env.driveMain();
+ env.driveMain();
- const jsContents = env.getContents('test.js');
- expect(jsContents).toContain('imports: [[RouterModule.forRoot()]]');
+ 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');
+ const dtsContents = env.getContents('test.d.ts');
+ expect(dtsContents).toContain(`import * as i1 from 'router';`);
+ expect(dtsContents)
+ .toContain('i0.ɵNgModuleDefWithMeta');
+ });
+
+ it('should extract the generic type if it is provided as qualified type name', () => {
+ 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';
+ import * as internal from './internal';
+
+ declare class RouterModule {
+ static forRoot(): ModuleWithProviders;
+ }
+ `);
+
+ env.write('node_modules/router/internal.d.ts', `
+ export declare class InternalRouterModule {}
+ `);
+
+ 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', () => {