fix(ivy): properly compile NgModules with forward referenced types (#29198)

Previously, ngtsc would resolve forward references while evaluating the
bootstrap, declaration, imports, and exports fields of NgModule types.
However, when generating the resulting ngModuleDef, the forward nature of
these references was not taken into consideration, and so the generated JS
code would incorrectly reference types not yet declared.

This commit fixes this issue by introducing function closures in the
NgModuleDef type, similarly to how NgComponentDef uses them for forward
declarations of its directives and pipes arrays. ngtsc will then generate
closures when required, and the runtime will unwrap them if present.

PR Close #29198
This commit is contained in:
Alex Rickabaugh
2019-03-08 17:57:34 -08:00
committed by Kara Erickson
parent 1625d86178
commit 73da2792c9
13 changed files with 210 additions and 65 deletions

View File

@ -732,7 +732,7 @@ export class TestBedRender3 implements Injector, TestBed {
* @internal
*/
_getComponentFactories(moduleType: NgModuleType): ComponentFactory<any>[] {
return moduleType.ngModuleDef.declarations.reduce((factories, declaration) => {
return maybeUnwrapFn(moduleType.ngModuleDef.declarations).reduce((factories, declaration) => {
const componentDef = (declaration as any).ngComponentDef;
componentDef && factories.push(new ComponentFactory(componentDef, this._moduleRef));
return factories;
@ -820,3 +820,14 @@ class R3TestCompiler implements Compiler {
class R3TestErrorHandler extends ErrorHandler {
handleError(error: any) { throw error; }
}
/**
* Unwrap a value which might be behind a closure (for forward declaration reasons).
*/
function maybeUnwrapFn<T>(value: T | (() => T)): T {
if (value instanceof Function) {
return value();
} else {
return value;
}
}