Home > Mobile >  How do I get rid of this overload error when I extend Express' Request object?
How do I get rid of this overload error when I extend Express' Request object?

Time:12-19

I'm trying to extend Express' Request object so that I can access req.user, but I keep running into an overload error. I tried both of these solutions here but they don't work for me.

EDIT: I am using passport.js and jwt

Extend Express Request object using Typescript

Unable to extend Express Request in TypeScript

I have tried extending Express' Request object in different two ways:

  1. Using interface extend. This works (kind of) but I get an overload error so I can't compile using 'tsc':

overload error

// index.d.ts file

import { IUser } from "../models/user";
import { Request } from "express";


export interface IUserRequest extends Request {
  user: IUser; // or any other type
}
  1. Creating a global namespace. This does not work because I am unable to access the req.user property. I have tried importing { Request } from "express" but this doesn't work for this option because it says Request is declared but never used:
//index.d.ts file

import { IUser } from "../models/user";
// import { Request } from "express"

export {};

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

This is my post controller that's trying to access req.user:

export const admin_code_post = [
  body("admin_code", "Wrong code buddy")
    .trim()
    .escape()
    .custom((value: string) => {
      if (value !== process.env.SECRET_CODE) {
        throw new Error("Admin code is incorrect");
      }
      return true;
    }),
  (req: IUserRequest, res: Response, next: NextFunction) => {
    const errors = validationResult(req);

    if (!errors.isEmpty()) {
      res.render("admin_code", {
        title: "Enter Code",
        errors: errors.array(),
        user: req.user,
      });
      return;
    }

    User.findOneAndUpdate(
      { username: req.user?.username }, // issue here if I create a global namespace
      { admin: true },
      (err: Error, user: IUser) => {
        if (err) return next(err);

        res.render("index", {
          title: "Welcome",
          user,
        });
      }
    );
  },
];

Unable to find req.user when using global namespace method

This is my tsconfig.json :

{
    "compilerOptions": {
      "target": "es2016",   
      "module": "commonjs", 
      "rootDir": "./src",   
      "typeRoots": [
        "./node_modules/@types",
        "./types"
      ],                    
      "sourceMap": true,    
      "outDir": "dist",     
      "noEmitOnError": true,
      "esModuleInterop": true,
      "forceConsistentCasingInFileNames": true,           
      "strict": true,                                   
      "noImplicitAny": true
    },
    "include": ["./src/**/*"],
    "exclude": ["node_modules"],
    "ts-node": {
      "files": true
    },
    "files": [
      "./src/types/index.d.ts"
    ]
  }
  

What am I doing wrong? Any advice would be appreciated.

CodePudding user response:

Your 2nd approach should work with the following changes,

import { IUser } from "../models/user";

// export {}; <-- you don't need this

declare global {
  namespace Express {
    export interface Request { // <-- you have to export the interface
      user?: IUser;
    }
  }
}

Make sure this code is in a *.d.ts file. Please check the documentation to learn more about how namespaces & declaration merging works

UPDATE

Just noticed that you use passport js. If you check the index.d.ts file of the passport js you can find following code lines,

declare global {
    namespace Express {
        // tslint:disable-next-line:no-empty-interface
        interface AuthInfo {}
        // tslint:disable-next-line:no-empty-interface
        interface User {} // <-- empty interface

        interface Request {
            authInfo?: AuthInfo | undefined;
            user?: User | undefined; // <-- using that as the type of req.user

so the one we define won't work. You can try,

const user = req.user as IUser example

or you can change your index.d.ts as,

// see - https://stackoverflow.com/a/63973683/11306028
export {};

declare global {
  namespace Express {
    interface User {
      first_name: string;
      last_name: string;
      username: string;
      email: string;
      admin: boolean;
    }
  }
}
  • Related