Angular中@Input设置默认值导致继承抽象类的组件测试报错
问题原因
- 核心是Angular 12搭配对应版本TypeScript的类继承依赖注入逻辑,和子类实例属性初始化的执行顺序冲突导致:
- 当子类
AComponent没有显式声明构造函数时,Angular默认会自动透传父类需要的依赖注入参数给super() - 但如果子类存在带默认值的实例属性(这里就是
@Input() foo = true),TypeScript转译后的代码会调整初始化逻辑,导致父类构造函数执行时,本该注入的FormBuilder还没有被正确绑定到this上,就会出现访问this.formBuilder为undefined的报错 - 去掉@Input的默认值后,子类没有实例属性初始化逻辑,透传注入的逻辑恢复正常,测试即可正常运行
- 当子类
解决方案
方案1:子类显式声明构造函数,透传依赖
最稳妥的解法,直接在AComponent里显式写构造函数,把父类需要的FormBuilder注入并传给super即可:
import {FormBuilder} from '@angular/forms'; export class AComponent extends BComponent<any> implements OnInit { @Input() foo = true; // 新增构造函数,显式注入父类需要的依赖并透传 constructor(formBuilder: FormBuilder) { super(formBuilder); } ngOnInit(): void { super.ngOnInit(); } }
该方案不需要修改父类逻辑,兼容所有业务场景。
方案2:将父类表单初始化逻辑移到ngOnInit中
符合Angular最佳实践,避免在构造函数中执行业务逻辑,等依赖注入完全完成后再执行初始化:
import {FormControl} from '@angular/forms'; export abstract class BComponent<T> implements OnInit { @Input() value: T; protected a: FormControl; constructor(protected formBuilder: FormBuilder) {} ngOnInit(): void { // 把表单控件初始化移到生命周期钩子中执行 this.a = this.formBuilder.control(null); } }
方案3:升级Angular版本
该问题是Angular 12及更早版本的已知问题,Angular 13+版本已经修复了该场景下的依赖注入逻辑,升级到13及以上版本也可以解决问题。
内容的提问来源于stack exchange,提问作者m0e
相关产品推荐
相关产品推荐

