拆分Angular类至独立文件后测试报错:依赖注入构造函数不兼容
问题背景
原本将两个实现相同方法的类放在同一文件中,后拆分至两个文件,让基类实现ItemHandler接口:
基类代码
@Injectable({providedIn: 'root'}) export class PlatformItemHandler implements ItemHandler<PlatformSwimlaneItem> {
子类代码
@Injectable({providedIn: 'root'}) export class PlatformTemplateItemHandler extends PlatformItemHandler {
运行测试时触发依赖注入错误:
Error: This constructor is not compatible with Angular Dependency Injection because its dependency at index 16 of the parameter list is invalid.
完整报错日志
22:22:54 Error: This constructor is not compatible with Angular Dependency Injection because its dependency at index 16 of the parameter list is invalid. 22:22:54 This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator. 22:22:54 22:22:54 Please check that 1) the type for the parameter at index 16 is correct and 2) the correct Angular decorators are defined for this class and its ancestors. 22:22:54 at <Jasmine> 22:22:54 at ɵɵinvalidFactoryDep (/bazel-out/k8-fastbuild/bin/cake/node_modules/@angular/core/fesm5/core.goog.js:861:11) 22:22:54 at NodeInjectorFactory.TemplateListComponent_Factory [as factory] (ng:///TemplateListComponent/ɵfac.js:13:66) 22:22:54 at getNodeInjectable (/bazel-out/k8-fastbuild/bin/cake/node_modules/@angular/core/fesm5/core.goog.js:3944:44) 22:22:54 at instantiateAllDirectives (/bazel-out/k8-fastbuild/bin/cake/node_modules/@angular/core/fesm5/core.goog.js:8333:25) 22:22:54 at createDirectivesInstances (/bazel-out/k8-fastbuild/bin/cake/node_modules/@angular/core/fesm5/core.goog.js:7723:5) 22:22:54 at ɵɵelementStart (/bazel-out/k8-fastbuild/bin/cake/node_modules/@angular/core/fesm5/core.goog.js:14479:9) 22:22:54 at BrandTemplateComponent_ng_container_7_ng_template_12_lucid_template_list_3_Template (ng:///BrandTemplateComponent.js:214:5) 22:22:54 at executeTemplate (/bazel-out/k8-fastbuild/bin/cake/node_modules/@angular/core/fesm5/core.goog.js:7696:9) 22:22:54 at renderView (/bazel-out/k8-fastbuild/bin/cake/node_modules/@angular/core/fesm5/core.goog.js:7521:13) 22:22:54 at TemplateRef.createEmbeddedView (/bazel-out/k8-fastbuild/bin/cake/node_modules/@angular/core/fesm5/core.goog.js:10364:17) 22:22:54 HeadlessChrome 86.0.4240 (Linux 0.0.0): Executed 24 of 28 (4 FAILED) (skipped 3) (0 secs / 18.19 secs)
查看测试文件构造函数,索引16(从0开始)的参数为private visibleTemplateList: VisibleTemplateList,该类本身是可注入的:
@Injectable({providedIn: 'root'}) export class VisibleTemplateList extends Pipe<TemplateWithValues[]> {
已尝试以下方案但未解决问题:
- 使用抽象类替代接口
- 移除基类的
@Inject()装饰器 - 尝试StackOverflow相关问题的所有解决方案
问题原因
报错看似指向VisibleTemplateList,但实际根源是基类PlatformItemHandler的依赖注入元数据未被Angular正确解析:
- 若基类存在构造函数依赖,子类继承时未显式调用父类构造函数并传递所有依赖,导致Angular生成的工厂函数参数不匹配。
- 拆分文件后,模块导入路径错误或增量构建缓存,导致Angular无法识别基类的
@Injectable装饰器,触发“祖先类缺少装饰器”的潜在问题,最终错误定位到无关组件的参数上。 - Angular的DI系统在处理继承关系时,需要确保父类的装饰器元数据能被正确读取,拆分文件可能破坏了这种元数据传递链。
解决方案
显式传递父类构造函数依赖
如果基类有构造函数参数,子类必须显式调用super()并传递所有依赖,示例:@Injectable({providedIn: 'root'}) export class PlatformTemplateItemHandler extends PlatformItemHandler { constructor(dep1: DepType1, dep2: DepType2 /* 所有父类依赖 */) { super(dep1, dep2); } }验证基类装饰器与导入配置
确认基类的@Injectable({providedIn: 'root'})配置正确,且基类文件被正确导入到使用子类的模块中,避免路径错误导致元数据丢失。清理构建缓存
执行项目清理命令(如ng clean或对应Bazel的清理指令)后重新构建,清除增量构建缓存的旧元数据。检查测试模块配置
在测试的TestBed中显式提供PlatformItemHandler或PlatformTemplateItemHandler,确保测试环境能正确解析这两个类的依赖。
内容的提问来源于stack exchange,提问作者Mauricio Gracia Gutierrez

