Home > Blockchain >  How do I add custom property to Express.Request in Typescript?
How do I add custom property to Express.Request in Typescript?

Time:02-16

I'm sorry for my poor English skills.

I created a new project using express-generator-typescript.

$ npx express-generator-typescript --use-yarn

I want to add additional properties to Express.Request for my custom middleware. So I created types/myRequest.d.ts in ./src and put and save the code as below:

// myRequest.d.ts
declare namespace Express {
  interface Request {
    myProp?: boolean;
  }
}

And I uncommented "typeRoots" in tsconfig.json and added "./node_modules/@types", "./src/types", and I tried to use the added property by creating a some middleware in ./src/routes/api.ts. Here's the full code:

// api.ts
import { NextFunction, Request, Response, Router } from "express";
import userRouter from "./user-router";

function myMiddleware(req: Request, _res: Response, next: NextFunction) {
  req.myProp = true;
  next();
}

// Export the base-router
const baseRouter = Router();

// Setup routers
baseRouter.use("/users", myMiddleware, userRouter);

// Export default.
export default baseRouter;

This builds fine, also IntelliSense in VS Code works fine and doesn't show any issues. However, when I run yarn start:dev I get the following error:

/home/me/dev/express-gen-ts/node_modules/ts-node/src/index.ts:828
    return new TSError(diagnosticText, diagnosticCodes);
           ^
TSError: ⨯ Unable to compile TypeScript:
src/routes/api.ts:5:7 - error TS2339: Property 'myProp' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.

5   req.myProp = true;
        ~~~~~~

    at createTSError (/home/me/dev/express-gen-ts/node_modules/ts-node/src/index.ts:828:12)
    at reportTSError (/home/me/dev/express-gen-ts/node_modules/ts-node/src/index.ts:832:19)
    at getOutput (/home/me/dev/express-gen-ts/node_modules/ts-node/src/index.ts:1022:36)
    at Object.compile (/home/me/dev/express-gen-ts/node_modules/ts-node/src/index.ts:1326:43)
    at Module.m._compile (/home/me/dev/express-gen-ts/node_modules/ts-node/src/index.ts:1458:30)
    at Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Object.require.extensions.<computed> [as .ts] (/home/me/dev/express-gen-ts/node_modules/ts-node/src/index.ts:1462:12)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19) {
  diagnosticCodes: [ 2339 ]
}
[nodemon] app crashed - waiting for file changes before starting...

So I can't do development in dev state. Of course if I don't use additional properties, the dev state is also available and works fine.

I think express-generator-typescript itself has some setting. Because changing "typeRoots" in tsconfig.json doesn't change the result. But I couldn't find it.

Thank you in advance.

CodePudding user response:

I suggest you a way and hope it helps you.

in the file ./src/routes/api.ts you add this code (under import)

declare global {
     namespace Express {
         interface Request {
             myProp?: boolean;
         }
     }
}

then run again (doesn't seem to need types/myRequest.d.ts file)

CodePudding user response:

Whenever I run into this type of problem, I usually use "declare module" to add properties to Express's "Request" interface instead of declaring them in a namespace. This way I usually don't have to change anything in the tsconfig nor add any .d.ts files.

Add these lines to your api.ts code (note that in most cases you will need to reference the express-serve-static-core module as this is where the Request interface is declared):

declare module "express-serve-static-core" {
  interface Request {
    myProp?: boolean;
  }
}

Full file:

// api.ts
import { NextFunction, Request, Response, Router } from "express";
import userRouter from "./user-router";

declare module "express-serve-static-core" {
  interface Request {
    myProp?: boolean;
  }
}

function myMiddleware(req: Request, _res: Response, next: NextFunction) {
  req.myProp = true;
  next();
}

// Export the base-router
const baseRouter = Router();

// Setup routers
baseRouter.use("/users", myMiddleware, userRouter);

// Export default.
export default baseRouter;

Normally this should make your newly added property available in other files as well, but you can of course export the manipulated Request interface just to be safe.

  • Related