Register
{ provide: "MAIL_SENDER", useClass: SmtpMailSender } and inject with @Inject("MAIL_SENDER") private mail: MailSenderRegister a string token with useClass and inject it with @Inject("MAIL_SENDER"). Interfaces don't exist at runtime. So Nest can't use them as tokens, and it can't read them from type metadata. You keep the interface only as the TypeScript type.
"constructor(private mail: MailSender) {} with providers: [SmtpMailSender]" is wrong, because Nest has no runtime type to match. "constructor(@Inject(MailSender) private mail: MailSender) {}" is wrong for the same reason: MailSender is not a value at runtime. "Mark MailSender with @Injectable() so it can be used as a token" is wrong, because decorators can't be put on interfaces.
An abstract class would also work as a token. An interface never does.
Read more