ts-node: Can't extend express Request type

I’ve tried this, this, etc

// ./typings/express/index.d.ts
declare namespace Express {
  export interface Request {
     token?: string
  }
}

Example usage:

import * as express from 'express'

(req: express.Request, res: express.Response, next: express.NextFunction) => {

  const foo = req.token

}

It does work if I compile directly (tsc -p .), it does work in Visual Code, but when I try to run with ts-node I always get:

error TS2339: Property ‘token’ does not exist on type ‘Request’.

Any idea how can I make it work with ts-node?

Versions: ts-node@7.0.1 typescript@3.0.1

https://stackoverflow.com/q/53765895/340760

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 5
  • Comments: 25 (9 by maintainers)

Most upvoted comments

Please see the README and CHANGELOG, and possibly search past issues to find why it was changed.

Thanks to this comment by @blakeembrey, I got my declaration merges working! All you need to do is put "./typings" before "./node_modules/@types".

"typeRoots": ["./typings", "./node_modules/@types"]

To help anyone who is just looking for something else to try here is what worked for me when trying to extend ExpressJS’ Request. I had to have tried more than a dozen things before getting this to work:

  • Flip the order of what everyone is recommending in the “typeRoots” of your tsconfig.json (and don’t forget to drop the src pathing if you have a rootDir setting in tsconfig such as “./src”). Example:
"typeRoots": [
      "./node_modules/@types",
      "./your-custom-types-dir"
]
  • Example of custom extension ('./your-custom-types-dir/express/index.d.ts"). I had to use inline import and default exports to use classes as a type in my experience so that is shown too:
declare global {
  namespace Express {
    interface Request {
      customBasicProperty: string,
      customClassProperty: import("../path/to/CustomClass").default;
    }
  }
}
  • Update your nodemon.json file to add the “–files” command to ts-node, example:
{
  "restartable": "rs",
  "ignore": [".git", "node_modules/**/node_modules"],
  "verbose": true,
  "exec": "ts-node --files",
  "watch": ["src/"],
  "env": {
    "NODE_ENV": "development"
  },
  "ext": "js,json,ts"
}

The following worked for me:

// project-root/src/types/express/index.d.ts
declare global {
    namespace Express {
        interface Request {
            token?: string
        }
    }
}

And then run

ts-node --files ./src/server.ts

As ts-node does not use files because of slows startup time, we need to tell it explicitly. Hence ‘–files’ is necessary here.

With --files in ts-node command local declaration files are recognized. Example command: ts-node --files src/index.ts

Can you guys @3mard @blakeembrey tell WHY this works? I would like understand more 😃 Also is this the best solution for this problem or is it only a workaround?

Thanks to this comment by @blakeembrey, I got my declaration merges working! All you need to do is put "./typings" before "./node_modules/@types".

"typeRoots": ["./typings", "./node_modules/@types"]

Still not working Screen Shot 2020-01-17 at 23 24 41

I solved this issues like this (req as any).something = object; it works for me

Same. I can’t make it work. Neither solution helps. Yours is an ugly hack but works for sure.

My problem is that VSCode recognizes it, and all is green. But when I try to run it with ts-node, it gives the error.

@brunolm @henrikra I created this repo example https://github.com/3mard/ts-node-example for extending express request

This worked for me:

  • create express.d.ts file in typings folder with contents
declare module 'express-serve-static-core' {
  interface Request {
    foo?: string
  }
}

As this is confusing a lot of people to get right, I’d suggest setting up a working example in the docs

@brunolm That wouldn’t work because it’d just discover the first one, not all of them. You can always use the /// <reference /> directive to resolve the one you specifically want to extend (and put your typeRoots first, otherwise you’re just resolving @types anyway - it may even work by just switching the order of typeRoots above and no need for reference since one is a module and the other definition is global).

Works for me… I add “–files” flag in the run command “ts-node --files index.ts”, and create express.d.ts with the follow content.

declare namespace Express { export interface Request { user_id: number; } }

You need to import or export something to indicate that the file is a module. If you are not importing anything then simply add

export {};

in that file, then the error should be gone.

VSCode gives me:

Augmentations for the global scope can only be directly nested in external modules or ambient module declarations.ts(2669)