Search code examples
typescriptclassdependency-injectionnestjsnest

In Nestjs, Providing abstract class to module doesn't work properly


const userRepositoryProvider = {
  provide: UserRepository, // abstract class
  useClass: ConcreteUserRepository, // concrete class
};

In module A, I'm providing and exporting a provider which looks like above. (all of them set to injectable)

In another module B, I'm importing module A. and In a service of module B, I'm injecting the provider which is imported from module A, like :

private readonly userRepo: UserRepository

and when I build and execute the app, Nest doesn't resolve the dependency, telling UserRepository is "?".


Strange thing is, when I set the provider provide token to string like:

const userRepositoryProvider = {
  provide: "UserRepository", // abstract class
  useClass: ConcreteUserRepository, // concrete class
};

and inject the provider like :

@Inject("UserRepository") private readonly userRepo: UserRepository

it works perfectly as I intended without any exception.

So why does it behave like this? Is it maybe a bug?


Lastly, I provide those two abstract and concrete classes. but I think it doesn't matter since string provide token works properly while abstract class provide token doesn't.

@Injectable()
export abstract class UserRepository {
  getUser(id: bigint): User {
    return User.create(id);
  }
}

@Injectable()
export class ConcreteUserRepository extends UserRepository {}
const userRepositoryProvider = {
  provide: UserRepository, // abstract class
  useClass: ConcreteUserRepository, // concrete class
};

In module A, I'm providing and exporting a provider which looks like above. (all of them set to injectable)

In another module B, I'm importing module A. and In a service of module B, I'm injecting the provider which is imported from module A, like :

private readonly userRepo: UserRepository

and when I build and execute the app, Nest doesn't resolve the dependency, telling UserRepository is "?".


Strange thing is, when I set the provider provide token to string like:

const userRepositoryProvider = {
  provide: "UserRepository", // abstract class
  useClass: ConcreteUserRepository, // concrete class
};

and inject the provider like :

@Inject("UserRepository") private readonly userRepo: UserRepository

it works perfectly as I intended without any exception.

So why does it behave like this? Is it maybe a bug?


Lastly, I provide those two abstract and concrete classes. but I think it doesn't matter since string provide token works properly while abstract class provide token doesn't.

@Injectable()
export abstract class UserRepository {
  getUser(id: bigint): User {
    return User.create(id);
  }
}

@Injectable()
export class ConcreteUserRepository extends UserRepository {}

  • properly working case enter image description here

  • improperly working case enter image description here

  • the error log enter image description here


Solution

  • Though I haven't resolved the problem yet, I found that the Nest framework is not the direct reason.

    My server-side application runs on AWS Lambda environment.

    Maybe some problems happen during either transpiling, bundling, or maybe execution etc.

    When I get the reason, I will update this.


    I got the reason..! Actually I don't know the fundamental reason but I got the solution.

    I changed all my import paths to absolute paths. and it works. I think the issue occurred during esbuild bundling time.

    and I had to inject all dependencies in constructors manually with @Inject()