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

使用Tsyringe依赖注入时控制器方法中service实例为undefined的问题

Tsyringe依赖注入中控制器方法内this.userService为undefined的问题

我在使用Tsyringe结合Express控制器、服务与仓库实现依赖注入时遇到问题:服务与仓库的依赖注入正常工作,但控制器仅能在构造函数中访问注入的UserService,当通过Postman调用路由触发控制器的getUserById方法时,控制台输出serverInstance undefined并返回500错误。

控制器代码

import { Request, Response } from 'express'
import { RequestResult } from '../../contracts/requestHandle/request-result'
import {inject, injectable } from 'tsyringe'
import { UserDto } from '../../contracts/transfer-objects/user-dto'
import { UserLoginDto } from '../../contracts/transfer-objects/user-login-dto'
import IUserService from '../../contracts/interfaces/services/user-service-interface'

@injectable()
export class UserController {
    constructor(
        @inject("UserService")
        private userService?: IUserService 
    ){
        this.userService!.getUserById('1').then((teste) => {
            console.log("teste", teste)
        })
    }

    async getUserById(request: Request, response: Response<RequestResult<UserDto | null>>){
        try{
            console.log("serverInstance", this.userService)
            const entity = await this.userService!.getUserById(request.params.id)
            return response.status(200).json(entity)
        }catch(err){
            const result = new RequestResult<any>(null, true, "Erro ao buscar o usuário")
            return response.status(500).json(result)
        }
    }
}

服务代码

import { inject, injectable, Lifecycle, scoped } from "tsyringe"
import { UserModel } from "../contracts/entities/user-model"
import { UserDto } from "../contracts/transfer-objects/user-dto"
import { sign } from "jsonwebtoken"
import { RequestResult } from "../contracts/requestHandle/request-result"
import automapper from "../contracts/utils/automapper"
import type IUserRepository from "../contracts/interfaces/repositories/user-repository-interface"
import IUserService from "../contracts/interfaces/services/user-service-interface"
import { UserLoginDto } from "../contracts/transfer-objects/user-login-dto"
import { RequestAnswer } from "../contracts/requestHandle/request-answer"

@injectable()
export class UserService implements IUserService {
    
    constructor(
        @inject("UserRepository")
        private userRepository: IUserRepository
    ){}

    async getUserById(userId: string) : Promise<RequestResult<UserDto | null>>{
        console.log("getUserById", userId)
        const id = parseInt(userId)
        const userModel = await this.userRepository.getUserById(id)

        if(userModel){
            const result = automapper.map("UserDto", UserDto, userModel)

            return new RequestResult<UserDto>(result) 
        }
        else{
            return new RequestResult<null>(null, false, "Usuário não encontrado.")
        }
    }
}

仓库代码

import { context } from '../../repository/context/dbContext'
import { UserModel } from '../../contracts/entities/user-model'
import IUserRepository from '../../contracts/interfaces/repositories/user-repository-interface'

export class UserRepository implements IUserRepository {
    
    async getUserById(userId: number) : Promise<UserModel | null> {
        console.log("getUserById", userId)
        const user = await context.user.findFirst({ where: { id: userId } })
        return user
    }
}

DI配置代码

import { container } from "tsyringe"
import { UserService } from "../business/user-service"
import { UserRepository } from "../repository/repositories/user-repository"

import IUserRepository from "../contracts/interfaces/repositories/user-repository-interface"
import IUserService from "../contracts/interfaces/services/user-service-interface"
import { UserController } from "./controllers/user-controller"

container
    .registerSingleton(UserController)
    .registerSingleton<IUserRepository>("UserRepository", UserRepository)
    .registerSingleton<IUserService>("UserService", UserService)

问题原因

构造函数中this.userService正常是因为实例化控制器时,this指向当前控制器实例;但通过Express路由调用方法时,方法的this上下文丢失了——Express会直接调用传入的方法回调,此时this不再指向控制器实例(严格模式下变为undefined)。

解决方案

有两种常用的修复方式:

1. 路由注册时绑定this上下文

在注册路由时,使用bind方法将控制器实例绑定到方法上,确保方法执行时this指向控制器实例:

import { container } from 'tsyringe';
import { UserController } from './controllers/user-controller';
import express from 'express';

const app = express();
const userController = container.resolve(UserController);

// 绑定this到控制器实例
app.get('/users/:id', userController.getUserById.bind(userController));

2. 使用箭头函数定义控制器方法

箭头函数不会创建自己的this,会继承构造函数中的this上下文,修改控制器方法定义为箭头函数:

@injectable()
export class UserController {
    constructor(
        @inject("UserService")
        private userService?: IUserService 
    ){
        this.userService!.getUserById('1').then((teste) => {
            console.log("teste", teste)
        })
    }

    // 改为箭头函数
    getUserById = async (request: Request, response: Response<RequestResult<UserDto | null>>) => {
        try{
            console.log("serverInstance", this.userService)
            const entity = await this.userService!.getUserById(request.params.id)
            return response.status(200).json(entity)
        }catch(err){
            const result = new RequestResult<any>(null, true, "Erro ao buscar o usuário")
            return response.status(500).json(result)
        }
    }
}

两种方式都能解决this.userService为undefined的问题,可根据项目习惯选择。


内容的提问来源于stack exchange,提问作者Eduardo Angelim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 15:27:22