typescript - Nest kan ikke løse avhengigheter for [ServiceName]
Feilen som sier at avhengigheten ikke kan løses, er ikke klar nok. For øyeblikket sier feilmeldingen:
[ExceptionHandler] Nest can't resolve dependencies of the LeadService (LeadRepository, ?). Please make sure that the argument dependency at index [1] is available in the LeadModule context.
Fra dette resultatet kan jeg konkludere med at avhengigheten ConsentService til min LeadService. Se LeadService-konstruktøren nedenfor.
I tillegg legger utdataene også frem følgende forslag:
Potensielle løsninger:
- Hvis avhengigheten er en leverandør, er den en del av gjeldende LeadModule?
Mitt svar: Det er en leverandør, men det er ikke en del av det nåværende modul. Det er en leverandør fra ConsentModule. Se ConsentModule-definisjonen.
- Hvis en avhengighet eksporteres fra en separat @Module, blir den modulen importert i LeadModule?
@Module({
imports: [ /* the Module containing dependency */ ]
})
Mitt svar: Ja, det eksporteres fra ConsentModule og det importeres i LeadModule, så jeg forstår ikke hvorfor dette feiler.
Inndatakode
Samtykketjeneste
@Injectable()
export class ConsentService {
constructor(@InjectRepository(Consent) private repository: Repository<Consent>) {}
}
Ledelsestjeneste
@Injectable()
export class LeadService<T extends LeadPayload> {
constructor(
@InjectRepository(Lead)
private leadRepository: Repository<Lead>,
@Inject()
private consentService: ConsentService
) {}
}
Samtykkemodul
import { Module } from '@nestjs/common';
import { ConsentService } from './consent.service';
import { Consent } from '../db/models';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [TypeOrmModule.forFeature([Consent])],
providers: [ConsentService],
exports: [ConsentService]
})
export class ConsentModule {}
LedendeModul
import { Module } from '@nestjs/common';
import { LeadService } from './lead.service';
import { Lead } from '../db/models';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConsentModule } from './consent.module';
@Module({
imports: [ConsentModule, TypeOrmModule.forFeature([Lead])],
providers: [LeadService],
exports: [LeadService]
})
export class LeadModule {}
AppModul
@Global()
@Module({
imports: [
ConsentModule,
LeadModule,
TypeOrmModule.forRoot({
...getDbConnectionProperties(),
entities: [Consent, Lead]
})
],
controllers: [
DevController,
HealthController
],
providers: []
})
export class AppModule {}
Jeg vil gjerne vite hvorfor feilen skjer nøyaktig, fordi jeg tror jeg har deklarert alt riktig
Svar #1
Når du bruker @Inject må du oppgi token (ID-en) som containeren bruker for å finne objektinstansen. Dette er nyttig når du for eksempel har flere instanser av en klasse. Du kan gi hver instans (en egendefinert leverandør) et navn/ID (et strengtoken i Nest-termer) og deretter @Inject("name") slik at Nest vil injisere riktig instans av objektet.
Så for din LeadService ser det ikke ut til at Nest vet hvilken instans som skal injiseres i consentService-parameteren fordi du ikke har spesifisert en token. Fordi Nest kan gjøre matching ved å bruke klassetypen som token, kan du skrive @Inject(ConsentService). Nest vil forstå at det må instansiere en instans av ConsentService (med alle dens avhengigheter løst) og deretter gi det objektet til LeadService-konstruktøren.
Men ofte når du bruker klassetypen som token, er det fordi du bare har én instans av klassen. Så du kan droppe @Inject(ConsentService) helt. Nest kan matche basert på typene og injisere en instans (en singleton-instans). Så for applikasjonen din, fjern bare @Inject()-deklaratoren fra consentService-konstruktørparameteren.
Nå skal jeg foreslå at du ikke bruker @Inject() i det hele tatt. Hvorfor? Fordi etter min mening bryter det prinsippet om Inversjon av kontroll. Poenget med IoC er at objektet som mottar injeksjonen (LeadService) ikke skal vite hva det blir injisert med. Alt som betyr noe er at de injiserte objektene oppfyller typekontrakten. Så hvis du for eksempel har to instanser av ConsentService, hvilken skal LeadService bruke? Vel, LeadService skal ikke vite det, men @Inject() kobler LeadService til en implementasjon av ConsentService, noe som begrenser gjenbrukbarheten/sammensattheten til de to klassene. Hvis man følger gode SOLID-prinsipper, vil man kanskje komponere objekter i forskjellige kombinasjoner. Etter min mening er den riktige måten å bruke egendefinert provider-metadata for å spesifisere hvordan objekter skal kobles sammen ved hjelp av strengtoken.