Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to extend Express Request in TypeScript

This question has been asked several times, but none of the answers that were given have worked for me. I'm trying to extend the Express Request object to include a property to store a User object. I created a declaration file, express.d.ts, and placed it in the same directory as my tsconfig.json:

import { User } from "./src/models/user";

declare namespace Express {
    export interface Request {
        user: User;
    }
}

Then I try to make an assignment to it in secured-api.ts:

import express from 'express';
import { userService } from '../services/user';

router.use(async (req, res, next) => {
    try {
        const user = await userService.findByUsername(payload.username);

        // do stuff to user...

        req.user = user;
        next();
    } catch(err) {
        // handle error
    }
});

I get the following error:

src/routes/secured-api.ts:38:21 - error TS2339: Property 'user' does not exist on type 'Request'.

38                 req.user = user;
                       ~~~~

My User class is:

import { Model, RelationMappings } from 'objection';

export class User extends Model {

    public static tableName = 'User';
    public static idColumn = 'username';

    public static jsonSchema = {
        type: 'object',
        required: ['fname', 'lname', 'username', 'email', 'password'],

        properties: {
            fname: { type: 'string', minLength: 1, maxLength: 30 },
            lname: { type: 'string', minLength: 1, maxLength: 30 },
            username: { type: 'string', minLength: 1, maxLength: 20 },
            email: { type: 'string', minLength: 1, maxLength: 320 },
            password: { type: 'string', minLength: 1, maxLength: 128 },
        }
    };

    public static modelPaths = [__dirname];

    public static relationMappings: RelationMappings = {

    };

    public fname!: string;
    public lname!: string;
    public username!: string;
    public email!: string;
    public password!: string;
}

My tsconfig.json is:

{
    "compilerOptions": {
      "target": "es6",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
      "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
      "lib": ["es2015"],                             /* Specify library files to be included in the compilation. */
      "outDir": "./build",                      /* Redirect output structure to the directory. */
      "strict": true,                           /* Enable all strict type-checking options. */
      "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
    }
}

My directory structure is:

backend/
    package.json
    tsconfig.json
    express.d.ts
    src/
        models/
            user.ts
        routes/
            secured-api.ts

What am I doing wrong here?

like image 403
user3814613 Avatar asked Jan 03 '19 21:01

user3814613


People also ask

Does typescript work with Express?

Express and Typescript packages are independent. The consequence of this is that Typescript does not “know” types of Express classes. There is a specific npm package for the Typescript to recognize the Express types.

How do I get a body in Express?

JSON Request Body Express has a built-in express. json() function that returns an Express middleware function that parses JSON HTTP request bodies into JavaScript objects. The json() middleware adds a body property to the Express request req . To access the parsed request body, use req.

What is req user in Express?

You generally use the req. body object to receive data through POST and PUT requests in the Express server. In your index.js file, set a POST request to the route '/login' : // POST https://example.com/login // // { // "email": "[email protected]", // "password": "helloworld" // } app.


1 Answers

The problem is that you are not augmenting the Express global namespace defined by express you are creating a new namespace in your module (the file becomes a module once you use an import).

The solution is to declare the namespace in global

import { User } from "./src/models/user";

declare global {
    namespace Express {
        export interface Request {
            user: User;
        }
    }
}

Or not use the module import syntax, just reference the type:

declare namespace Express {
    export interface Request {
        user: import("./src/models/user").User;
    }
}
like image 169
Titian Cernicova-Dragomir Avatar answered Sep 19 '22 15:09

Titian Cernicova-Dragomir