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

NestJS中服务跨模块注入后内部属性失效问题求助

NestJS嵌套Service调用时DAO内部属性失效的问题解决

问题场景

使用NestJS + MikroORM开发REST应用,采用整洁架构做模块抽象,出现以下异常:

  • 控制器直接注入并调用Service A(IBusinessDao实现):完全正常
  • 控制器调用Service B(AuthService),再由Service B调用Service A:Service A内部的repo属性为undefined,抛出TypeError: Cannot read properties of undefined (reading 'repo')

依赖链简化:

Controller C <- Service B (AuthServiceModule) <- Service A (MikroDatabaseModule) : 失效
Controller C <- Service A (MikroDatabaseModule) : 正常

核心错误代码

AuthService中的问题代码

async createAuth(phone: string, userId: string): Promise<UserAuthEntity> {
  const payload = { sub: userId, phone: phone };
  return this.jwtService
    .signAsync(payload)
    .then(
      (token) => new UserAuthEntity(0, userId, phone, token, Status.Normal),
    )
    .then(this.dao.userAuth.create); // 问题根源
}

错误栈

TypeError: Cannot read properties of undefined (reading 'repo')
  at create (/home/serveradmin/mrmap/server/mainline/src/iac/database/mikro/dao/mikro-base.dao.ts:26:17)
  at processTicksAndRejections (node:internal/process/task_queues:95:5)
  at async AuthController.implByService (/home/serveradmin/mrmap/server/mainline/src/api/auth/auth.controller.ts:31:19)

问题原因

将this.dao.userAuth.create作为回调传给then时,函数的this指向丢失:此时create方法执行时,this不再指向MikroBaseDao实例,而是变为全局对象(严格模式下为undefined),导致无法访问this.repo。

而控制器中直接调用this.dao.userAuth.create(entity)时,通过实例调用方法,this会正确绑定到MikroBaseDao实例,因此能正常访问repo。

解决方案

方案1:用箭头函数包裹回调(最推荐)

通过箭头函数保留外层上下文的this,确保create方法的调用者是MikroBaseDao实例:

async createAuth(phone: string, userId: string): Promise<UserAuthEntity> {
  const payload = { sub: userId, phone: phone };
  return this.jwtService
    .signAsync(payload)
    .then(
      (token) => new UserAuthEntity(0, userId, phone, token, Status.Normal),
    )
    .then(entity => this.dao.userAuth.create(entity)); // 箭头函数绑定上下文
}

方案2:提前绑定方法的this指向

在MikroBusinessDao初始化MikroBaseDao时,手动把create方法绑定到实例:

@Injectable()
export class MikroBusinessDao implements IBusinessDao, OnApplicationBootstrap {
    userAuth: IBaseDao<UserAuthEntity>;
    constructor(
        @InjectRepository(UserAuthEntity)
        private _authRepo: EntityRepository<UserAuthEntity>,
    ) {}
    onApplicationBootstrap() {
        const baseDaoInstance = new MikroBaseDao(this._authRepo);
        // 绑定create方法的this到baseDaoInstance
        this.userAuth = {
          ...baseDaoInstance,
          create: baseDaoInstance.create.bind(baseDaoInstance)
        } as IBaseDao<UserAuthEntity>;
    }
}

方案3:将MikroBaseDao的方法改为箭头函数

箭头函数会自动捕获当前上下文的this,避免绑定丢失:

export class MikroBaseDao<T extends object> implements IBaseDao<T> {
    constructor(private repo: EntityRepository<T>) {}
    // 改为箭头函数
    async create = (item: T): Promise<T> => {
        // 原方法逻辑,此时this.repo可正常访问
        ...
    }
}

验证

修改后重新启动应用,调用implByService方法即可正常执行,不会再抛出repo未定义的异常。

内容的提问来源于stack exchange,提问作者Li Zhenxin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 22:04:58