DEV Community

Discussion on: Why You Should Inject Interfaces, Not Classes, in NestJS Applications ?

Collapse
 
micalevisk profile image
Micael Levi L. C.

I like to use the abstract classes typescript feature as interfaces so I can use it as a token for the provider as well and avoid the @Inject() decorator. For example:

export abstract class IUserService {
  abstract getUserById(id: string): Promise<User>;
}

export class UserService implements IUserService {
  getUserById(id: string): Promise<User> {
    // ...
  }
}

@Module({
  providers: [
    {
      provide: IUserService,
      useClass: UserService,
    }
  ]
})
export class AppModule {
  constructor(private readonly userService: IUserService) {}
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
bilelsalemdev profile image
bilel salem • Edited

Good point, I didn’t think of it before — thanks!
But I want to clarify something :
For the Abstract Classes :
✖ Cons:

  • Not a true interface: Abstract classes can have implementation details or state, which may be unwanted if you're strictly defining a contract.
  • Tight coupling to class inheritance: Your implementation is forced to extend the abstract class.

For the Interfaces :
✔ Pros:

  • Pure abstraction: Interfaces are cleaner contracts — no logic, just structure.
  • More flexible: You can implement multiple interfaces, which isn't possible with class inheritance.
  • Better alignment with Domain-Driven Design (DDD): Interfaces are ideal for defining service boundaries.

Some comments have been hidden by the post's author - find out more