phzonta
phzonta

Reputation: 793

implement express controller class with typescript

I'm doing an express app with typescript. The router code is:

let user = new User();
router.get("/", user.test);

the user class is

export class User {
   test(req, res, next) {
      // this === undefined
   }
}

the problem is that the this object is undefined inside test method. Is there a better way to implement express routing?

Upvotes: 14

Views: 27946

Answers (3)

With the new version of TS, you can create a static method with or without an accessor modifier, and call that method in the router without instantiating a class:

export class UserController {
    // arrow function
    public static test: RequestHandler = async (req, res, next) => {
        // ...
    }

    // regular function
    public static async getAll(req: Request, res: Response, next: NextFunction) 
    {
        // ...
    }
}

and in the router use it as:

import { Router } from "express";
import { UserController } from '/controllers/UserController';

const router = Router();

...
router.get('/test', UserController.test);
....

Upvotes: 0

mtpultz
mtpultz

Reputation: 18248

You can use export default and instantiate the controller so it can be used without instantiation in whichever file you've imported the controller.

register.controller.ts

import { Router, Request, Response, NextFunction } from 'express';

class Register {

    constructor() {    
      this.register = this.register.bind(this);
    }

    register(req: Request, res: Response, next: NextFunction) {
      // ... removed for brevity
    }
}

export default new Register();

server.ts or auth.routes.ts

import registerCtrl from '../controllers/auth/register.controller.js';

// ... removed for brevity

router.post('/register', registerCtrl.register);

Upvotes: 18

Nitzan Tomer
Nitzan Tomer

Reputation: 164129

You need to use the bind function to keep the scope of this when the method is invoked:

let user = new User();
router.get("/", user.test.bind(user));

Or you can do that in the User constructor:

export class User {
    constructor() {
        this.test = this.test.bind(this);
    }

    test(req, res, next) {
        ...
    }
}

Another option is to use an arrow function:

let user = new User();
router.get("/", (req, res, next) => user.test(req, res, next));

Upvotes: 33

Related Questions