itsundefined
itsundefined

Reputation: 1450

Extending existing properties on @types declarations

I am trying to extend the Request object of express that is available on express.Request so that it includes some other data inside the session. I have tried creating my own typings file (d.ts) and using the following code:

import * as express from 'express';

declare module 'express' {
    export interface Request {
        session: express.Request['session'] & {
            myOwnData: string;
        }
    }
}

I am greeted with the following error:

'session' is referenced directly or indirectly in its own type annotation.

What is the correct way to implement this?

Upvotes: 5

Views: 2169

Answers (1)

Greg Rozmarynowycz
Greg Rozmarynowycz

Reputation: 2085

So looking at the express-session type declaration, it declares a Session (and modified Request object) under the Express namespace. Using this we can create a type declaration (mySession.dt.s) to augment the default properties, bypassing the limits of declaration merging:

import {Express} from 'express';
import 'express-session';

declare module 'express' {
    export interface Request {
        session: Express.Session & {
            myOwnData: string;
            myOwnData2: number;
            myOwnData3: boolean;
        };
    }
}

Note that it seems that the compiler is somewhat flexible about the imports in this file (like it doesn't seem to care if Express or Request is imported), but being explicit will be most consistent.

We can then import this declaration into our server file:

import express = require('express');
import {Express, Request, Response} from 'express';
import './mySession';
import * as session from 'express-session';

const app: Express = express();
const PORT = process.env.PORT || process.env.NODE_PORT || 3000;

app.use('/endpoint', (req: Request, res: Response) => {
   const a: number = req.session.myOwnData3 + 2; // fails to compile and highlighted by editors
   console.log(req.session.myOwnData); // compiles and provided autocomplete by Webstorm
   // do stuff
   return res.ok();
});

app.use(session(/** do session stuff **/));

log.info(`Start Express Server on ${PORT}`);
app.listen(PORT);

As tested, this structure achieves type-safety on the added properties, and intellisense/autocomplete in both VSCode and WebStorm with both the express-session and added properties.

Unfortunately, as you noted, this won't be applied globally where type inference is utilized, (only where you explicitly import Request). If you want full control over the interface, you could uninstall @types/express-session and just copy & modify the d.ts (and import that). Another possibility is to declare a totally new property and implement, but obviously a lot more work.

Upvotes: 4

Related Questions