Nest не может разрешить зависимости [ServiceName] - PullRequest
4 голосов
/ 30 марта 2020

Ошибка, которая говорит о том, что зависимость не может быть разрешена, недостаточно ясна. В настоящее время вывод об ошибке гласит:

[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.

Из этого вывода я могу сделать вывод, что зависимость ConsentService от моего LeadService. См. LeadService конструктор ниже.

Кроме того, в выводе также содержится следующее предложение:

Потенциальные решения:

  • Если зависимость является поставщиком, является ли он частью текущего LeadModule?

Мой ответ: Это поставщик, но он не является частью текущего модуля. Это провайдер из ConsentModule. Смотрите определение ConsentModule.

  • Если зависимость экспортируется из отдельного модуля @Module, импортируется ли этот модуль в LeadModule?
   @Module({
     imports: [ /* the Module containing dependency */ ]
   })

Мой ответ: Да, он экспортируется из ConsentModule, и он импортируется в LeadModule, поэтому я не понимаю, почему это не получается.

Код ввода

ConsentService

@Injectable()
export class ConsentService {
  constructor(@InjectRepository(Consent) private repository: Repository<Consent>) {}
}

LeadService

@Injectable()
export class LeadService<T extends LeadPayload> {
  constructor(
    @InjectRepository(Lead)
    private leadRepository: Repository<Lead>,
    @Inject()
    private consentService: ConsentService
  ) {}
}

ConsentModule

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 {}

LeadModule

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 {}

AppModule

@Global()
@Module({
  imports: [
    ConsentModule,
    LeadModule,
    TypeOrmModule.forRoot({
      ...getDbConnectionProperties(),
      entities: [Consent, Lead]
    })
  ],
  controllers: [
    DevController,
    HealthController
  ],
  providers: []
})
export class AppModule {}

Я хотел бы знать, почему именно происходит ошибка, потому что я думаю, что все правильно объявил

1 Ответ

4 голосов
/ 30 марта 2020

Когда вы используете @Inject, вам необходимо указать token (идентификатор), который контейнер использует для поиска экземпляра объекта. Это удобно, когда, например, у вас есть несколько экземпляров класса. Каждому экземпляру ( Пользовательский поставщик ) можно присвоить имя / идентификатор (строковый токен в терминологии Nest), а затем @Inject("name"), чтобы Nest внедрил правильный экземпляр объекта.

Так что для вашего LeadService Nest, похоже, не знает, какой экземпляр внедрить в параметр consentService, потому что вы не указали токен. Поскольку Nest может выполнять сопоставление, используя тип класса в качестве токена, вы можете написать @Inject(ConsentService). Nest поймет, что ему нужно создать экземпляр экземпляра ConsentService (с разрешением всех его зависимостей) и затем предоставить этот объект конструктору LeadService.

Однако часто, когда вы используете тип класса в качестве это потому, что у вас есть только один экземпляр класса. Таким образом, вы можете полностью отказаться от @Inject(ConsentService). Гнездо может соответствовать на основе типов и внедрить экземпляр (экземпляр singleton ). Поэтому для вашего приложения просто удалите декоратор @Inject() из параметра конструктора consentService.

Теперь я собираюсь предложить вам вообще не использовать @Inject(). Почему? Потому что ИМО нарушает идею Инверсия контроля . Суть Io C заключается в том, что инъекционер (LeadService) не должен знать, что ему вводят. Все, что имеет значение, - это то, что внедренные объекты соответствуют типовому контракту. Например, если у вас есть два экземпляра ConsentService, какой из них следует использовать LeadService? Ну, LeadService не должен знать, но @Inject() соединяет LeadService с реализацией ConsentService, которая ограничивает возможность повторного использования / компоновки двух классов. Если вы следуете хорошим принципам SOLID, вы можете составлять объекты в разных комбинациях. ИМО правильный способ - использовать метаданные Custom Provider, чтобы указать, как соединять объекты вместе, используя строковые токены.

...