Tolga Oguz
Tolga Oguz

Reputation: 162

How to work with Property Based Injection when extending class

I have a certain use case where I need to do property-based injection of a provider in a parent class but somehow the provider class is not captured by dependency injection, thus being returned as undefined.

Below is my parent class which basically contains some functions to perform pagination, sorting etc to handle rest queries. This is not a module, maybe this is the reason.

One thing that may be off here is that BaseService is not a NestJS Module, it's just a stand-alone service file that exports this class.

import { Model } from 'mongoose';
import { UtilsProvider } from 'src/utils/utils.service';
export class BaseService<MongooseModelT extends Record<string | number, any>>
  implements OnModuleInit
{
  private utilsProvider: UtilsProvider; // always returned undefined 
  constructor(private mongooseModel: Model<DocumentType<MongooseModelT>>) {}
  
  async transform(){
   ... Some logic that uses UtilsProvider
  }
}

An example service that extends this BaseService,

@Injectable()
export class CompaniesService extends BaseService<CompanyDocument> {
  constructor(
    @InjectModel(Company.name) private companyModel: Model<CompanyDocument>,
  ) {
    super(companyModel);
  }
  create(createCompanyDto: CreateCompanyDto) {
    return this.companyModel.create(createCompanyDto);
  }
}

Companies module,

import { Module } from '@nestjs/common';
import { CompaniesService } from './companies.service';
import { CompaniesController } from './companies.controller';
import { MongooseModule } from '@nestjs/mongoose';
import { Company, CompanySchema } from './schemas/company.schema';

@Module({
  imports: [
    MongooseModule.forFeature([{ name: Company.name, schema: CompanySchema }]),
  ],
  controllers: [CompaniesController],
  providers: [CompaniesService],
})
export class CompaniesModule {}

UtilsProvider is exported from a module and it is in global scope,

@Global()
@Module({
  providers: [UtilsProvider],
  exports: [UtilsProvider],
})
export class UtilsModule {}

I also tried wrapping BaseService with a module and importing it in the app.module.ts file since maybe that's why it's not capturing dependency injection, but that did not work either.

Upvotes: 1

Views: 2350

Answers (1)

HMilbradt
HMilbradt

Reputation: 4639

From the docs,

"...you can use the @Inject() decorator at the property level."

Changing your base class to the following should fix the issue:

import { Inject } from '@nestjs/common';
import { Model } from 'mongoose';
import { UtilsProvider } from 'src/utils/utils.service';
export class BaseService<MongooseModelT extends Record<string | number, any>>
  implements OnModuleInit
{
  @Inject(UtilsProvider) // Must have @Inject
  private utilsProvider: UtilsProvider; // Will now be defined
  constructor(private mongooseModel: Model<DocumentType<MongooseModelT>>) {}
  
  async transform(){
   ... Some logic that uses UtilsProvider
  }
}

Seems to be an unfortunate difference here between property and constructor based injection that isn't mentioned anywhere else.

Upvotes: 1

Related Questions