Website-Suche

node.js - Wie kann ich Typen mit Middleware von Express handhaben?


Ich benutze Typescript in Node.js. Wenn man Express-Middleware verwendet, transformiert man oft das Request-Objekt. Mit Typescript konnten wir jedoch nicht verfolgen, wie das Request-Objekt transformiert wurde. Wenn man die Middleware kennt, die vorher ausgeführt wurde, gibt es eine Möglichkeit, den Typ des Requests daraus zu erkennen? Wenn das in Express nicht möglich ist, würde ich gerne ein anderes Framework finden, wo es möglich ist. Ist es in Nest (https://github.com/kamilmysliwiec/nest) möglich?

Beispielcode

import { Request, Response, NextFunction } from 'express';

function userMiddleware(req: Request & User, res: Response, next: NextFunction) {
    req.user = {
        id: 'user_id',
    };
    next();
}

interface User {
    user: {
        id: string;
    }
}

interface Middleware {
    <T>(req: Request & T, res: Response, next: NextFunction): void;
}

class Controller {
    middleware = [userMiddleware];

    get = new GetMethod(this.middleware);

    post = (req: Request /* I don't know exact req type */, res: Response, next: NextFunction) => {
        console.log(req.user) // Error!
    }
}

class GetMethod {
    constructor(middleware: Middleware[]) {
        // How to deduce type of req from Middleware array?
    }
}

const controller = new Controller();

express.use('/', controller.middleware, controller.post);

Ich möchte Typinformationen aus der Middleware-Liste in der Controller-Klasse extrahieren.

Antwort #1

Zuerst denke ich, dass die richtige Schnittstelle ist

interface User {
  id: string;
}

Da sie Callbacks sind, erhalten sie standardmäßige Request, die kein user in ihrer Signatur haben.

Daher haben Sie 2 Möglichkeiten: eine Typumwandlung vorzunehmen oder eine benutzerdefinierte Deklaration zu schreiben. Beides ist in Ordnung, wenn Sie es richtig machen.

Typumwandlung:

interface User {
  id: string;
}

const isObject = (value: unknown): value is {[key: string]: unknown} => {
  return value && typeof value === 'object';
};

const isReqWithUser = (req: Request): req is Request & {user: User} => {
  return isObject(req) && !!req.user;
}

class Controller {
  post = (req: Request, res: Response, next: NextFunction) => {
    if (isReqWithUser(req)) {
      console.log(req.user) // now it works
    }
    next();
  }
}

Zollerklärung:

Aber wir müssen verstehen, dass der Benutzer nicht immer in der Anfrage vorhanden ist und wir ihn als optional markieren sollten.

interface User {
  id: string;
}

declare module 'express' {
  export interface Request {
    user?: User; // adding our custom declaration.
  }
}

class Controller {
  post = (req: Request, res: Response, next: NextFunction) => {
    console.log(req.user) // now it works
    next();
  }
}

Verwandte Artikel