Angular 5继承带依赖注入的类出现类型错误的问题求助
为什么TypeScript会报TS2415错误,以及正确的继承注入方式
先解释第一个TS2415错误的根源
你碰到的TS2415错误,核心在于TypeScript私有成员的可见性规则:
- 父类
FooService里的private _bar是完全封装在父类内部的,子类ExtFooService根本无法继承或访问这个成员。 - 当你在子类里再次声明
private _bar: BarService时,相当于在子类里创建了一个和父类同名但完全独立的私有成员——TypeScript会判定这违反了继承的一致性规则,因此抛出错误。
再说说移除注入后出现的TS2554错误
当你删掉子类里的private _bar后,super()报TS2554是因为父类的构造函数明确要求传入一个BarService实例。子类初始化时必须先调用super()完成父类的构造,而父类的构造逻辑依赖这个参数,所以你必须给super()传值,满足父类的构造要求。
关于你提出的解决方案:不是必须换变量名
你给出的用_extBar的写法是可行的,但其实还有更合理的处理方式,不需要刻意更换变量名:
方案1:把父类成员改成protected(推荐)
如果希望子类能访问这个成员,把父类的private改成protected——这样子类可以继承该成员,同时外部无法访问,兼顾封装性和继承需求:
@Injectable() class FooService { constructor(protected _bar: BarService) {} } @Injectable() class ExtFooService extends FooService { constructor(_bar: BarService) { super(_bar); // 现在子类可以直接访问this._bar } }
这里子类构造函数里不需要加private/protected修饰符,因为我们不需要在子类重新声明成员,只需要把注入的参数传给super()即可,父类的_bar会被继承下来。
方案2:子类构造函数只传参不声明成员
如果不需要在子类里直接访问_bar,甚至可以简化成这样(可读性稍差,但逻辑清晰):
@Injectable() class ExtFooService extends FooService { constructor(bar: BarService) { super(bar); } }
或者保持下划线命名风格,但不加修饰符:
@Injectable() class ExtFooService extends FooService { constructor(_bar: BarService) { super(_bar); } }
这样不会在子类创建新的私有成员,只是把注入的参数传递给父类构造函数,完全符合要求。
方案3:保留父类private,但子类不重复声明
如果父类的_bar必须是private(完全不让子类访问),那子类只需要注入BarService并传给super()即可,不要在子类里声明同名的私有成员:
@Injectable() class FooService { constructor(private _bar: BarService) {} } @Injectable() class ExtFooService extends FooService { constructor(private _extBar: BarService) { super(_extBar); // 这里子类不能访问this._bar,但因为DI容器注入的是单例,_extBar和父类的_bar是同一个实例 } }
这就是你提到的写法,功能上是正常的,只是子类没必要重复持有同一个实例的引用,除非你有特殊需求。
总结
- 绝对不要在子类重复声明父类的
private成员,这违反TypeScript的继承规则 - 子类构造函数必须调用
super(),并传入父类构造函数所需的所有参数 - 优先选择把父类成员改成
protected的方案,既满足继承访问需求,又保证封装性
内容的提问来源于stack exchange,提问作者Sampgun
相关产品推荐
相关产品推荐

