Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't extend express Request type #745

Closed
brunolm opened this issue Dec 13, 2018 · 29 comments
Closed

Can't extend express Request type #745

brunolm opened this issue Dec 13, 2018 · 29 comments

Comments

@brunolm
Copy link

brunolm commented Dec 13, 2018

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: [email protected] [email protected]

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

@blakeembrey
Copy link
Member

What’s your tsconfig.json?

@brunolm
Copy link
Author

brunolm commented Dec 13, 2018

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "noImplicitAny": false,
    "sourceMap": true,
    "outDir": "dist",
    "experimentalDecorators": true,
    "esModuleInterop": true
  },
  "exclude": ["node_modules"]
}

I also tried with "typeRoots": ["./node_modules/@types", "./typings"]

@blakeembrey
Copy link
Member

@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).

@blakeembrey
Copy link
Member

Oh, also, you probably should just put your overrides in a different folder and it would be a non-issue. The problem is the conflict between two Express packages being resolved, but you can create a different package named something to do with your app or anything else that doesn’t conflict.

@3mard
Copy link
Contributor

3mard commented Dec 17, 2018

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

@brunolm
Copy link
Author

brunolm commented Dec 17, 2018

I don't fully understand why that's required now. I can confirm that this worked before:

versions

"typescript": "2.3.4",
"ts-node": "3.0.4",

tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "noImplicitAny": false,
    "sourceMap": true
  }
}

typings/foo.d.ts

declare module Express {
  export interface Request {
    knex: any;
    config: any;
    client: { id: number; name: string; };
  }
}

@blakeembrey
Copy link
Member

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

@blakeembrey
Copy link
Member

There is also an example in the README for adding custom types and modules. If you’d like to expand upon it, please feel free to submit a PR!

@blakeembrey
Copy link
Member

blakeembrey commented Dec 18, 2018

Just checked and we should invert the resolution order of types so it works as expected here.

Edit: The reason for the change is also in the README.

@henrikra
Copy link

henrikra commented Feb 19, 2019

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?

@brunolm
Copy link
Author

brunolm commented Feb 19, 2019

I gave up and started to do this:

req['token'] = 'foo'

And then casting to something when needed.

@3mard
Copy link
Contributor

3mard commented Feb 19, 2019

@henrikra I think this is a design decision that was made to optimize ts-node (why include .d.ts files that your app are not using anyway ?)

https://github.com/TypeStrong/ts-node/blob/master/src/index.ts#L481

@3mard
Copy link
Contributor

3mard commented Feb 19, 2019

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

@saoudrizwan
Copy link

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"]

@vschoener
Copy link

@saoudrizwan Thanks it works :)

@marcosfede
Copy link

marcosfede commented Dec 11, 2019

This worked for me:

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

@brunolm
Copy link
Author

brunolm commented Dec 12, 2019

@marcosfede your code makes everything be an any

image

If I delete your file the types work again.

@marcellsimon
Copy link

marcellsimon commented Feb 16, 2020

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.

@HarishAnkolekar24
Copy link

HarishAnkolekar24 commented Feb 26, 2020

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.

@brunolm
Copy link
Author

brunolm commented Feb 26, 2020

VSCode gives me:

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

@HarishAnkolekar24
Copy link

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.

@shane-js
Copy link

shane-js commented May 31, 2020

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"
}

@joshuanwafor
Copy link

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.

Worked for me. Thank you so much

@joaoromeira
Copy link

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

@galletafromjell666
Copy link

An alternative to using the --files tag with ts-node could be adding the ts-node property to the tsconfig.json:

tsconfig.json

{
  "ts-node": {
    "files": true
  },
  "compilerOptions":{
    // ...
  }
}

@pufex
Copy link

pufex commented Jun 13, 2024

@galletafromjell666 thanks bro! Worked for me :D

@scandela
Copy link

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"]

That also worked for me, thanks!

@LexxLuey
Copy link

LexxLuey commented Oct 30, 2024

An alternative to using the --files tag with ts-node could be adding the ts-node property to the tsconfig.json:

tsconfig.json

{
  "ts-node": {
    "files": true
  },
  "compilerOptions":{
    // ...
  }
}

You are the man. To God honest I tried every single solution until I at last tried yours and it worked. Saved me from pulling all my hair. If I may, why did the other solutions not work?

@Hussein-Ali-6
Copy link

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"
}

Saved my life, it works perfectly for me, Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests