Home > Software engineering >  Cannot read properties using regular method in controller, but works with arrow function
Cannot read properties using regular method in controller, but works with arrow function

Time:01-16

I am experiencing an issue where I am unable to use regular class methods to get access to userService.

I want to be able to write regular class methods in my user controller like this:

 public async register(req: Request, res: Response, next: NextFunction): Promise<Response | void> {
        try {
            const registerDTO: RegisterDTO = req.body;
            const user = await this.userService.register(registerDTO);
            res.status(201).json({ message: 'user created successfully.' });
        } catch (error) {
            next(error);
        }
    }

However when I change the above code to this:


 public register = async (req: Request, res: Response, next: NextFunction): Promise<Response | void>  => {
        try {
            const registerDTO: RegisterDTO = req.body;
            const user = await this.userService.register(registerDTO);
            res.status(201).json({ message: 'user created successfully.' });
        } catch (error) {
            next(error);
        }
    }

It works and data is being properly passed to the service. When I use arrow function instead of regular method it works just as I expect it to, but I prefer to use regular methods.

Then I have user routes like this where data is being passed to the controller:

 this.router.post('register', this.userController.register);

My user routes are injected with the controller and the controller gets the data, however it stops at the user controller and data doesn't get passed to userService and results in TypeError: Cannot read properties of undefined (reading 'userService')

I am expecting to be able to use regular methods instead of arrow functions. The error message Cannot read properties of 'userService' completely disappears when I change it to an arrow function, but is there a way to keep the regular function and not have to change it? I think that this has something to do with this. keyword? I am using inversify dependency injection and the service is being properly injected.

I also know that I can bind it, but I don't think that that is the correct solution. Do I also really have to change the regular methods to arrow functions or is there an approach which does not require such change?

CodePudding user response:

Your assumption regarding this keyword is right: inside a regular function, the value of this (the execution context) is dynamic and depends on how the function is invoked. However, inside an arrow function the value of this is always resolved lexically and not redefine throughout the lifecycle of the function.

So inside register function, the value of this is different when using an arrow function and when using regular function:

const user = await this.userService.register(registerDTO);

You can defined your own explicit binding using call or apply, not sure it make your code more readable:

this.router.post('register', (req, res, next) => this.userController.register.call(this.userController, req, res, next));
  • Related