0

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` });
    }
};

1 Answer 1

1

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
}
Sign up to request clarification or add additional context in comments.

4 Comments

I implemented your method, but then when I try to call the mongoose 'save()' method on req.user, It gives me error 'Property save does not exists on Type "RequestUser"'
RequestUser is just my example. You should use your own type instead of my RequestUser
See mongoose docs mongoosejs.com/docs/typescript.html you should have something similar to user: HydratedDocument<IUser>
I've updated the answer to fit your use case

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.