Home > OS >  typedi constructor injection return undefined
typedi constructor injection return undefined

Time:11-21

I'am using typedi in a Node (express) project. I can't understand why, in my service class, the injection works fine as property injection but not as constructor injection.

This works:

@Service()
export default class AuthService {
  @Inject("logger") private logger
  @Inject("eventEmitter")
  private eventEmitter!: EventEmitter;
   
  constructor(

  ) {}
}

While this is not working:

@Service()
export default class AuthService {
  @Inject("logger") private logger
  @Inject("eventEmitter")
  private eventEmitter!: EventEmitter;
   
  constructor(
      @Inject("logger") private logger,
      @Inject("eventEmitter") private eventEmitter: EventEmitter
  ) {}
}

As an example, I use the logger and the emitter as follows:

  public async SignUp(
    userInputDTO: IUserInputDTO
  ): Promise<{ user: IUser; token: string }> {
    try {
      //some code
      this.logger.silly("Hashing password");
      const hashedPassword = await argon2.hash(userInputDTO.password, { salt });
      this.logger.silly("Creating user db record");
      this.eventEmitter.emit(userEvent.signUp);
      //some code

      return {
        user: { },
        token: "myToken",
      };
    } catch (e) {
      this.logger.error(e);
      throw e;
    }
  }

In the first case it works as expected , but in the second case, this.eventEmitter and this.logger are undefined.

As a side note:

  • there aren't circular dependencies
  • I imported 'reflect-metadata', in fact the decorators work fine if they are placed on properties and not in the constructor's parameters
  • typedi, unless for this problem works fine. I can use Container#get , Container#set without any problem

CodePudding user response:

In the 2nd code snippet, you're already decorating AuthService with @Service(), which should be enough.

So change it to this and give it a try:

@Service()
export default class AuthService {

  constructor(
      private logger: YOU_NEED_A_TYPE_HERE,
      private eventEmitter: EventEmitter
  ) {}
}

Just make sure to change YOU_NEED_A_TYPE_HERE with the actual type of the logger, otherwise it won't work.

And then you should have your logger and eventEmitter references available:

public async SignUp(
    userInputDTO: IUserInputDTO
  ): Promise<{ user: IUser; token: string }> {
    try {
    
    // logger and eventEmitter should have the right values

CodePudding user response:

It started working, but I'm not sure what caused it.

  • I worked on another machine with a newer node version (the example in this question was ran on node12 while it started working with node16).

  • I added a line in the tsconfig.json that was missing.

    "emitDecoratorMetadata": true,

while "experimentalDecorators": true was already there.

Maybe it's time to setup a small container to test it in different node versions.

As a side note, it seems that adding explicit type to the constructor parameter to inject is not strictly required (but anyway suggested). Also the @Inject decorator seems also to be unnecessary as long as the class is already decorated with @Service

  • Related