Inversify子类通过super传参给父类报错问题排查
Inversify中通过super向父类传参时触发构造函数参数数量错误
错误信息
"message": "The number of constructor arguments in the derived class Child must be >= than the number of constructor arguments of its base class.",
"stack": "Error: The number of constructor arguments in the derived class Child must be >= than the number of constructor arguments of its base class.
相关代码
Parent.ts
import { injectable } from 'inversify'; interface IParentInterface { someMethod(): void; } @injectable() export class Parent implements IParentInterface { private readonly _topic: string; constructor(topic: string) { this._topic = topic; console.log('Parent constructor with topid', this._topic); } someMethod(): void { console.log('Parent method'); } }
Child.ts
import { injectable } from 'inversify'; import { Parent } from './Parent'; @injectable() export class Child extends Parent { constructor() { super('my_topic'); // 调用父类构造函数 console.log('Child constructor'); this.someMethod(); } }
types.ts
export const TYPES = { Parent: Symbol.for('parent'), Child: Symbol.for('Child') };
main.ts
const newContainers = new AsyncContainerModule(async (bind: interfaces.Bind) => { bind<Parent>(TYPES.Parent).to(Parent).inSingletonScope(); bind<Child>(TYPES.Child).to(Child).inSingletonScope(); }); const app = new AppServer( [newContainers], serviceGlobalCustomMiddlewares ); const childInstance = app.getContainer().get<Child>(TYPES.Child);
备注:移除super的参数后代码可正常运行。
问题原因
Inversify的@injectable()装饰器会校验类的构造函数参数规则:子类构造函数的参数数量必须大于等于父类的参数数量。这是因为Inversify依赖注入机制需要解析构造函数参数完成依赖注入,即便你手动通过super传参,只要子类构造函数参数数少于父类,容器就无法正确处理父类的注入逻辑,从而触发错误。
解决方案
方案1:让子类构造函数参数匹配父类,通过Inversify注入参数
如果topic需要动态注入,给子类添加对应参数,通过Inversify绑定具体值:
// Child.ts import { injectable, inject } from 'inversify'; import { Parent } from './Parent'; import { TYPES } from './types'; @injectable() export class Child extends Parent { constructor(@inject(TYPES.Topic) topic: string) { super(topic); console.log('Child constructor'); this.someMethod(); } } // types.ts 添加Topic标识 export const TYPES = { Parent: Symbol.for('parent'), Child: Symbol.for('Child'), Topic: Symbol.for('Topic') }; // main.ts 绑定topic常量值 const newContainers = new AsyncContainerModule(async (bind: interfaces.Bind) => { bind<Parent>(TYPES.Parent).to(Parent).inSingletonScope(); bind<Child>(TYPES.Child).to(Child).inSingletonScope(); bind<string>(TYPES.Topic).toConstantValue('my_topic'); });
方案2:修改父类,将参数改为可选或通过方法初始化
如果不需要通过构造函数传递topic,可以调整父类逻辑:
// Parent.ts @injectable() export class Parent implements IParentInterface { private _topic?: string; // 将构造函数参数设为可选 constructor(topic?: string) { this._topic = topic; topic && console.log('Parent constructor with topic', this._topic); } // 添加初始化方法设置topic initTopic(topic: string): void { this._topic = topic; console.log('Parent initialized with topic', this._topic); } someMethod(): void { console.log('Parent method'); } } // Child.ts @injectable() export class Child extends Parent { constructor() { super(); // 不传参数 this.initTopic('my_topic'); // 调用初始化方法赋值 console.log('Child constructor'); this.someMethod(); } }
方案3:移除父类的@injectable()装饰器
如果父类只是普通基类,不需要被Inversify管理,可以去掉它的@injectable(),容器就不会校验父类的构造函数参数:
// Parent.ts // 移除@injectable()装饰器 export class Parent implements IParentInterface { private readonly _topic: string; constructor(topic: string) { this._topic = topic; console.log('Parent constructor with topic', this._topic); } someMethod(): void { console.log('Parent method'); } } // Child.ts 保留@injectable() @injectable() export class Child extends Parent { constructor() { super('my_topic'); console.log('Child constructor'); this.someMethod(); } }
内容的提问来源于stack exchange,提问作者Mr X
相关产品推荐
相关产品推荐

