Angular10 IVY模式下带泛型的抽象组件基类如何正确添加装饰器
错误原因说明
- 使用
@Directive装饰器报错:Angular明确限制**@Directive装饰的类不能继承带@Component装饰的类**,你的父类SimpleComponent是组件类型,因此该方案不可行。 - 使用
@Component报错NG2003:你的抽象类构造参数中有泛型类型T extends BaseService<U>,TypeScript泛型会在编译期擦除,Angular的DI系统无法为未确定具体类型的泛型参数生成对应的注入令牌,因此编译器抛出找不到注入项的错误。
正确配置方案
基础方案(适配Angular 10及以上所有版本)
步骤1:为抽象基类加@Component装饰器
因为需要继承组件类,必须使用@Component装饰器,配置空模板即可,不需要额外选择器、样式等配置:
@Component({ template: '' }) export abstract class CrudAddEditComponent<U extends DomainObject, T extends BaseService<U>> extends SimpleComponent implements OnDestroy, OnInit { // 类原有实现保持不变 }
步骤2:为泛型依赖加@Optional装饰器
抽象类永远不会被直接实例化,不需要Angular为它注入泛型参数对应的service实例,只需要在构造函数的泛型service参数前添加@Optional()装饰器,告诉编译器这个参数是可选的,不需要强制查找注入令牌:
import { Optional } from '@angular/core'; constructor( messageService: MessageService, @Optional() protected service: T, protected route: ActivatedRoute, logger: NGXLogger ) { super(messageService, logger); }
你的子类实例化时需要在构造函数中调用super并传入具体的service实例,这部分逻辑和之前保持一致即可,运行时不会出现service为undefined的情况。
步骤3:避免将抽象基类加入模块声明
抽象类无法被实例化,不要把它加到任何NgModule的declarations、providers数组中,只有继承它的具体组件需要加入declarations。
优化方案(适配Angular 14及以上版本)
如果你的项目已经升级到Angular 14及以上版本,可以给@Component添加standalone: true配置,不需要把抽象基类加入任何模块,配置更简洁:
@Component({ template: '', standalone: true }) export abstract class CrudAddEditComponent<U extends DomainObject, T extends BaseService<U>> extends SimpleComponent implements OnDestroy, OnInit { // 类原有实现保持不变 }
内容的提问来源于stack exchange,提问作者csyperski
相关产品推荐
相关产品推荐

