How to handle NestJS Dependency Injection when extending a class for a service?
You can solve this by using a factory approach, try this:
Interface to determine the "shape" of your services:
export interface IDatabaseService { findOne(id: string): Promise<Cat>; count(): Promise<number>; testClass(): void;}
The BaseService must implement that interface:
export class BaseService implements IDatabaseService { constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) {} async findOne(id: string): Promise<Cat> { return await this.catModel.findOne({_id: id}); } async count(): Promise<number> { return await this.catModel.countDocuments(); } testClass() { console.log('BASE SERVICE CLASS USED'); }}
The dynamic services are not injected so they do not use the @Injectable()
decorator:
export class OtherService extends BaseService { constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) { super(catModel); } testClass() { console.log('OTHER SERVICE CLASS USED'); }}export class AnotherService extends BaseService { constructor(@InjectModel('Cat') public readonly catModel: Model<Cat>) { super(catModel); } testClass() { console.log('ANOTHER SERVICE CLASS USED'); }}
The factory class is the thing that gets injected:
@Injectable()export class DatabaseServiceFactory { constructor(@InjectModel('Cat') private readonly catModel: Model<Cat>) {} createService(name: string) : IDatabaseService { switch(name) { case 'other': return new OtherService(this.catModel); case 'another': return new AnotherService(this.catModel); default: throw new Error(`No service has been implemented for the name "${name}"`); } }}
export const catProviders = [ { provide: 'CatModelToken', useFactory: (connection: Connection) => connection.model('CAT', CatSchema), inject: ['DbConnectionToken'], }, { provide: 'BaseService', useFactory: (ConfigService: ConfigService, connection: Connection, dbFactory: DatabaseServiceFactory) => { const options = ConfigService.get('SERVICE_TYPE'); let model = connection.model('CAT', CatSchema); //return new BaseService(model).createService(options); return dbFactory.createService(options); }, inject: [ ConfigService, 'CatModelToken', 'DbConnectionToken', DatabaseServiceFactory ], }];