web-dev-qa-db-fra.com

Impossible d'étendre la demande expresse dans Typescript

Cette question a été posée à plusieurs reprises, mais aucune des réponses qui ont été données n'a fonctionné pour moi. J'essaie d'étendre l'objet express Request pour inclure une propriété pour stocker un objet User. J'ai créé un fichier de déclaration, express.d.ts, et placé dans le même répertoire que mon tsconfig.json:

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

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

Ensuite, j'essaie de faire une mission dans 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
    }
});

Je reçois l'erreur suivante:

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

38                 req.user = user;
                       ~~~~

Ma classe User est:

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

Mon tsconfig.json est:

{
    "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'. */
    }
}

Ma structure de répertoire est:

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

Qu'est-ce que je fais mal ici?

7
user3814613

J'ai eu le même problème ...

Vous ne pouvez pas simplement utiliser une demande étendue? aimer:

interface RequestWithUser extends Request {
    user?: User;
}
router.post('something',(req: RequestWithUser, res: Response, next)=>{
   const user = req.user;
   ...
}

Sur une autre note, si vous utilisez des rappels ASYNC avec Express, assurez-vous d'utiliser les wrappers Express-Async ou assurez-vous de savoir exactement ce que vous faites. Je recommande: Awaitjs

4
Nuno Sousa

J'ai essayé beaucoup de solutions mais aucune d'entre elles n'a travaillé.

mais cela peut être aussi simple aussi et fonctionnant parfaitement. Et bien sûr, vous pouvez économiser de l'authentification ailleurs.

import { IUser } from './src/_models/user.model';

export interface AuthenticatedRequest extends Request {
  user: IUser;
}
static async getTicket(req: AuthenticatedRequest, res: Response){}

METTRE À JOUR:

J'ai donc trouvé quelque chose d'intéressant d'ici: Importer la classe dans la définition du fichier (* d.ts) .

declare Namespace Express devrait être la première ligne à Thypscript le comptent comme mondial.

declare namespace Express {

  interface Request {
    user: import('./src/modules/models/user.model').IUser;
    uploadedImage: { key: string; type: string };
    group: import('./src/modules/models/group.model').IGroup;
  }
}
0
Eric Aska

Pour moi, je fais juste ça la façon paresseuse.

import { User } from '../database/models/user';

router.use(async (req, res, next) => {
   const user = req.user as User;
   // ...
});
0
Ahmed Kamal