Búsqueda de sitios web

javascript - En NestJs, ¿cómo inyectar un servicio basado en su interfaz?


Tengo el siguiente módulo: payment.module.ts

@Module({
  controllers: [PaymentController],
})
export class PaymentModule {}

Y en el siguiente servicio quiero tener acceso a un servicio basado en una interfaz

pago.servicio.ts

export class PaymentService {
   constructor(private readonly notificationService: NotificationInterface,
}

notificación.interfaz.ts

export interface NotificationInterface {
  // some method definitions
}

notificacion.servicio.ts

@Injectable()
export class NotificationService implements NotificationInterface {
  // some implemented methods
}

La pregunta es ¿cómo inyecto NotificationService basado en NotificationInterface?

Respuesta #1

Esta es la solución que encontré... usar Interfaces como tipos de valor no es posible ya que solo existen durante el desarrollo. Después de transpilar, las interfaces ya no existen, lo que resulta en valores de objeto vacíos. Sin embargo, hay una solución para tu problema usando claves de cadena como valores proporcionados y el decorador inject:

pago.modulo.ts

@Module({
  providers: [
    {
      provide: 'NotificationInterface',
      useClass: NotificationService
    }
  ]
})
export class PaymentModule {}

pago.servicio.ts

export class PaymentService {
   constructor(@Inject('NotificationInterface') private readonly notificationService: NotificationInterface,
}

Respuesta #2

Como mencionó Gabriel, no puedes usar interfaces ya que no están presentes en tiempo de ejecución, pero puedes usar una clase abstracta. Están disponibles en tiempo de ejecución, por lo que pueden usarse como tu token de inyección de dependencias.

En Typescript, las declaraciones de clases también crean tipos, por lo que también puedes implementarlos, no tienes que extenderlos.

Siguiendo tu ejemplo, podrías hacer lo siguiente:

notificación.interfaz.ts

export abstract class NotificationInterface {
  abstract send(): Promise<void>;
  // ... other method definitions
}

notificación.servicio.ts

export class NotificationService implements NotificationInterface {
  async send() {...}
} 

Luego, en tu módulo, proporciónalo así:

import NotificationInterface from "..."
import NotificationService from "..."

@Module({
  providers: [
    {
      provide: NotificationInterface,
      useClass: NotificationService
    }
  ]
})
export class PaymentModule {}

Y finalmente, usa el servicio inyectado a través de la interfaz en payments.service.ts

export class PaymentService {
   constructor(private readonly notificationService: NotificationInterface) {}
}

Ahora no necesitas proporcionar ningún token personalizado (como cadenas o símbolos) que estén algo "no relacionados" con la implementación de tu clase (y que solo sean un constructo de DI), pero puedes usar la estructura de tu modelo de POO.

Artículos relacionados