Angular11严格模式下ngComponentOutlet绑定懒加载组件类型不兼容问题
严格模式下组件懒加载的适配修正
报错核心原因
- 首个属性初始化报错,是TypeScript严格空值检查的强制要求:类属性要么在声明时给初始值,要么在构造函数里完成赋值,否则编译器会判定属性可能为undefined,抛出类型错误。
- 第二个模板类型不兼容报错,是之前为了解决第一个问题,给属性加上
| null可空类型、初始化为空值导致的——这个空类型会顺着async管道一路传到绑定层,再加上async管道本身在Promise没加载完的时候就会返回null,最终传给ngComponentOutlet的值就带上了多余的空类型,和组件入口的入参要求不匹配。
具体修正操作
- 改属性定义,去掉多余的空值类型
运行时逻辑里,这个headerComponent属性在组件初始化后就会立刻被赋值为动态import的Promise,从来不会出现null的运行时状态,完全没必要把类型设为可空,也不需要初始化为null。直接用TS的确定赋值断言绕开初始化检查即可:
这种写法不会引入多余的空类型,也能完全解决首个初始化报错的问题。// 末尾的!是确定赋值断言,告知编译器这个属性一定会在被访问前完成初始化 headerComponent!: Promise<Type<SiteAHeaderComponent>>; - 处理async管道的空值兼容问题
就算源类型不带空值,async管道在Promise没resolve的阶段,返回值固定是null。这块可以根据自己的偏好选两种方式处理:- 最省事的写法:在模板绑定处给async管道的返回值加非空断言,匹配
ngComponentOutlet的入参要求:<ng-template [ngComponentOutlet]="(headerComponent | async)!"></ng-template> - 更稳妥的写法:给加载等待阶段准备一个空占位组件,当async还没返回组件类的时候渲染占位组件,彻底解决类型不兼容问题,也不会出现空值渲染的报错:
先写一个无实际渲染逻辑的占位组件:
再把这个占位组件暴露到当前@Component({ template: '' }) export class EmptyPlaceholderComponent {}HeaderLoaderComponent的类上,让模板能访问到:
模板绑定时,把async返回的空值替换成占位组件:export class HeaderLoaderComponent implements OnInit { // 把占位组件挂成类属性,供模板使用 readonly EmptyPlaceholderComponent = EmptyPlaceholderComponent; // 修正后的懒加载属性 headerComponent!: Promise<Type<SiteAHeaderComponent>>; ngOnInit(): void { this.LoadHeaderComponent(); } private LoadHeaderComponent() { if (!this.headerComponent) { this.headerComponent = import(`../myFolder/siteA-header/siteA-header.component`) .then(({ SiteAHeaderComponent }) => SiteAHeaderComponent); } } }<ng-template [ngComponentOutlet]="(headerComponent | async) || EmptyPlaceholderComponent"> </ng-template>
- 最省事的写法:在模板绑定处给async管道的返回值加非空断言,匹配
后续扩展注意事项
- Ivy架构下,这种动态import的组件不需要额外在NgModule的
entryComponents数组里注册,只要保证动态import的路径准确,就能正常拆分懒加载chunk。 - 后续要做多场景头部加载的逻辑时,只需要在
LoadHeaderComponent方法里根据判断条件返回不同组件的动态import Promise即可,现有的类型逻辑不需要额外调整。
内容的提问来源于stack exchange,提问作者Roobot
相关产品推荐
相关产品推荐

