0
votes

I'm currently trying to work out a setup using NestJS injection, but I'm running into errors when trying to run the server.

The problem that I'm running into has to do with me trying to inject a class into a controller which extends an abstract class and I'm trying to set a property of the abstract class in the constructor.

Controller.ts

@Controller()
export class exampleController extends AbstractController {

  constructor(exampleClass: exampleInterface) {
    super(exampleClass);
  }

  @Get()
  getExample(): string {
    return 'Example';
  };
}

AbstractController.ts

export abstract class AbstractController {

  private exampleClass: ExampleInterface;

  constructor(exampleClass: ExampleInterface) {
    this.exampleClass = exampleClass;
  };

When I try to run my server, I get the following error:

Error: Nest can't resolve dependencies of the ExampleController (?). Please make sure that the argument Object at index [0] is available in the AppModule context.

I've added the class implementation to the app.module providers, but even then the error prevents me from running my code.

App.Module.ts

@Module({
  imports: [],
  controllers: [AppController, ExampleController],
  providers: [ExampleClass],
})
export class AppModule {}

ExampleClass.ts

@Injectable()
export class ExampleClass implements ExampleInterface {

  doSomething(): void {
    console.log('Hello World!');
  };
};

I've already tried different setups and looked at some other StackOverflow questions that advise to change up the provider in the app.module, but I haven't found one that worked for me yet. Any advise would be appreciated.

1

1 Answers

3
votes

Typescript interfaces are a compile time construct (they don't exist at all when the code is actually running), so there is no way for Nest to understand what parameter you're trying to inject.

You're going to have to specify your own Injection token with the provider configuration and then use that in the ExampleController constructor.

providers: [{ provide: 'ExampleToken', useClass: ExampleClass}]

and then you can inject it into your controller using ExampleToken (or whatever makes sense in your app)

@Controller()
export class exampleController extends AbstractController {

  constructor(@Inject('ExampleToken') exampleClass: exampleInterface) {
    super(exampleClass);
  }

  @Get()
  getExample(): string {
    return 'Example';
  };
}