Nest 无法解析 [ServiceName] 的依赖项

rav*_*ven 8 typescript typeorm nestjs

表示无法解决依赖关系的错误不够明确。目前,错误输出显示:

[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.
Run Code Online (Sandbox Code Playgroud)

从这个输出中,我可以得出结论,ConsentService我的LeadService. 请参阅LeadService下面的构造函数。

此外,输出还提出以下建议:

潜在的解决方案:

  • 如果依赖项是提供者,它是当前 LeadModule 的一部分吗?

我的回答:它是一个提供者,但它不是当前模块的一部分。它是来自 ConsentModule 的提供者。请参阅 ConsentModule 定义。

  • 如果从单独的 @Module 导出依赖项,则该模块是否在 LeadModule 中导入?
   @Module({
     imports: [ /* the Module containing dependency */ ]
   })
Run Code Online (Sandbox Code Playgroud)

我的回答:是的,它是从 ConsentModule 导出的,并在 LeadModule 中导入的,因此我不明白为什么会失败。

输入代码

同意服务

@Injectable()
export class ConsentService {
  constructor(@InjectRepository(Consent) private repository: Repository<Consent>) {}
}
Run Code Online (Sandbox Code Playgroud)

领先服务

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

同意模块

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

Run Code Online (Sandbox Code Playgroud)

引线模块

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

Run Code Online (Sandbox Code Playgroud)

应用程序模块

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

我想知道为什么会发生错误,因为我认为我已经正确声明了所有内容

kie*_*ans 9

使用时,@Inject您需要提供token容器用来查找对象实例的(id)。例如,当您有一个类的多个实例时,这很方便。您可以为每个实例(自定义提供程序)指定一个名称/ID(Nest 术语中的字符串标记),然后@Inject("name")Nest 将注入该对象的正确实例。

因此,您的LeadServiceNest 似乎不知道要向consentService参数中注入什么实例,因为您没有指定令牌。因为 Nest 可以使用类类型作为标记进行匹配,所以您可以编写@Inject(ConsentService). Nest 将意识到它需要实例化一个实例ConsentService(及其所有依赖项已解析),然后将该对象提供给LeadService构造函数。

然而,当您使用类类型作为标记时,通常是因为您只有该类的一个实例。所以你可以完全放弃@Inject(ConsentService)。Nest 可以根据类型进行匹配并注入实例(单例实例)。@Inject()因此,对于您的应用程序,只需从构造函数参数中删除装饰器即可consentService

现在,我建议您@Inject()根本不应该使用。为什么?因为在我看来,它违反了控制反转的思想。IoC 的要点是注入者 ( LeadService) 不应该知道它被注入了什么。重要的是注入的对象满足类型约定。例如,如果您有两个实例ConsentService,应该使用哪一个LeadService?好吧LeadService不应该知道,但@Inject()耦合到限制这两个类的可重用性/可组合性LeadService的实现。ConsentService如果遵循良好的SOLID原则,您可能希望以不同的组合来组成对象。IMO 正确的方法是使用自定义提供程序元数据来指定如何使用字符串标记将对象连接在一起。