You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS中使用抽象类作为Provider令牌无法解析依赖的问题

问题

在NestJS中,我在Module A中提供并导出如下Provider:

const userRepositoryProvider = {
  provide: UserRepository, // abstract class
  useClass: ConcreteUserRepository, // concrete class
};

所有类均已标记为@Injectable。在Module B中导入Module A后,在Module B的服务中注入UserRepository:

private readonly userRepo: UserRepository

构建运行应用时,Nest无法解析该依赖,提示UserRepository为"?"。

但将Provider的provide令牌改为字符串"UserRepository",并通过@Inject("UserRepository")注入时:

const userRepositoryProvider = {
  provide: "UserRepository",
  useClass: ConcreteUserRepository,
};
@Inject("UserRepository") private readonly userRepo: UserRepository

则可正常运行无异常。

相关抽象类与实现类代码如下:

@Injectable()
export abstract class UserRepository {
  getUser(id: bigint): User {
    return User.create(id);
  }
}

@Injectable()
export class ConcreteUserRepository extends UserRepository {}

请问为何会出现这种差异?是否属于Bug?

原因分析与解答

这不是NestJS的Bug,核心原因是TypeScript类型在编译后会被擦除,导致Nest的依赖注入系统无法通过类型令牌找到对应的Provider。

  • 当你用UserRepository(抽象类)作为provide令牌时,TypeScript编译成JavaScript后,这个抽象类的类型信息会丢失。Nest在运行时只能拿到一个空的类引用,无法正确关联到你定义的Provider,所以会提示无法解析依赖。
  • 改用字符串令牌"UserRepository"时,字符串在编译后会被保留,Nest可以直接通过这个明确的字符串标识找到对应的Provider,因此注入正常。

另外需要注意:虽然你给抽象类加了@Injectable(),但抽象类本身不能被实例化,Nest的DI系统需要明确的运行时标识来关联实现类。当使用类作为令牌时,Nest默认会尝试实例化该类,但抽象类做不到,这也是导致解析失败的一个辅助因素——即使类型信息没被擦除,Nest也无法实例化抽象类,而你通过useClass指定了实现类,但编译后的类型擦除让Nest找不到这个关联关系。

正确的实现方式有两种:

  1. 继续使用字符串或Symbol作为令牌,配合@Inject()装饰器完成注入
  2. 利用Nest的自定义令牌机制,确保运行时存在可被识别的唯一标识,避免依赖TypeScript的类型信息

内容的提问来源于stack exchange,提问作者JH Lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 18:42:35