Khushal Soni
Khushal Soni

Reputation: 1

How to add custom property in Express req object when using Typescript

I am trying to convert a user authentication API written in JavaScript to TypeScript. My auth middleware adds the 'user object' to 'req object' if user is authenticated, now when I try to access it in my Controllers, TypeScript gives error 'Property user does not exist on type Request'

I tried -

declare global {
    namespace Express {
        export interface Request {
            user?: any;
        }
    }
}

But if I give 'any' as type, then what will be meaning of Defining Types that I am using TypeScript for...

Router -

import express, { Router, Request, Response } from "express";

const router: Router = express.Router();

const userController = require("./../controllers/userController");
const auth = require("./../middleware/auth");

router.patch("/change-password", auth, userController.changePassword);

Auth Middleware -

const verifyJWT = async (req: Request, res: Response, next: NextFunction) => {
    try {
        const accessToken = req.headers["x-access-token"];
        if (!accessToken)
            return res.status(401).json({ error: `Token is required.` });

        const decodedToken = await jwt.verify(
            accessToken,
            config.ACCESS_TOKEN_KEY
        );
        if (!decodedToken)
            return res.status(403).json({ error: `Invalid Token.` });

        const user = await User.findOne({ _id: decodedToken._id, accessToken });
        if (!user) return res.status(400).json({ error: `No user found.` });

        req.user = user;
        req.accessToken = accessToken;

        next();
    } catch (err: any) {
        console.log("--MSG--" + err.message + "--NAME--" + err.name);

        if (err.name === "TokenExpiredError") {
            return res.status(401).json({
                error: "invalid_token",
                message: "The access token expired",
            });
        }

        res.status(500).json({
            error: "authentication_error",
            message: "Error while authenticating",
        });
    }
};
module.exports = verifyJWT;

Controller -

const changePassword: Function = async (req: Request, res: Response) => {
    try {
        // The auth middleware sets req.user with the user's document so I can use user document to Query the database.

        const { currentPass, newPass, confirmPass } = req.body;

        if (!currentPass || !newPass || !confirmPass) {
            return res
                .status(400)
                .json({ error: `Please fill all the required fields` });
        }

        if (newPass !== confirmPass) {
            return res.status(400).json({
                error: `New password doesn't match confirmation password`,
            });
        }

        if (req.user) {
            if (await bcrypt.compare(currentPass, req.user.password)) {
                req.user.password = newPass;
                await req.user.save();
                return res
                    .status(200)
                    .json({ result: 1, message: resMsgs.success.s4 });
            } else {
                return res.status(400).json({ error: `Wrong password` });
            }
        }
    } catch (err: any) {
        console.log(err.message);
        res.status(500).json({ error: `Something went wrong` });
    }
};

Upvotes: 0

Views: 826

Answers (1)

zoran404
zoran404

Reputation: 2946

In typescript you can declare what are the exports of a node module.

If the node module does not come with it's own types or if you want to modify it's types you can simply create additional declarations, like this:

declare module 'express'
{
    export interface Request
    {
        // if you're using mongoose
        user?: HydratedDocument<IUser>

        // if you're not using mongoose
        user?: IUser
    }
}

export interface IUser
{
    id: string
    name: string
}

Upvotes: 1

Related Questions