Typescript - 创建自定义快速中间件定义

hel*_*tan 9 node.js express typescript

我一直在尝试为我们的应用程序定义自定义中间件时遇到了困难。我正在使用 typescript@3.6.3 和 express@4.17.1。

我看到的所有输入中间件的示例都暗示用户没有向reqorres参数添加任何内容,但我知道这是中间件的重点 - 知道中间件必须是改变这些对象中的任何一个按特定顺序加载(即 cookie-parser 或 body-parser 在早期因这个而臭名昭著,我猜现在仍然是?)。无论如何,大多数示例都归结为类似 github 问题:https : //github.com/DefinitelyTyped/DefinitelyTyped/issues/26146#issuecomment-393386416

我遇到的问题是,我们确实改变了传递给每个中间件的reqres对象,因此我不得不相应地键入两个对象:

import {
    Express as ExpressInterface,
    Request as ExpressRequest,
    Response as ExpressResponse,
    NextFunction as ExpressNextFunction,
} from 'express';
import LoggerType from 'some-log-package';

// don't do anything different the `next()`
export type ExpressNextFunction = ExpressNextFunction;

export interface CustomServerApp extends ExpressInterface {
    customHeader: string;
    customLogger: LoggerType;
}

export interface CustomServerRequest extends ExpressRequest {
    app: CustomServerApp,
    id: string,
    urlSearchParams: URLSearchParams,
    // etc
}

export interface CustomServerResponse extends ExpressResponse { ... }
Run Code Online (Sandbox Code Playgroud)

所以我导出中间件的基本参数:

  • req = CustomServerRequest
  • res = CustomServerResponse
  • next = ExpressNextFunction

当然,我将它们相应地导入到我的中间件文件中:

import {
    CustomServerRequest,
    CustomServerResponse,
    ExpressNextFunction
} from './server-types'

export const customMiddleware = (req: CustomServerRequest, res: CustomServerResponse, next: ExpressNextFunction): void {
    // do something here with either `req` or `res` or both!
    next()
};

Run Code Online (Sandbox Code Playgroud)

我们有一个集中式middleware.ts文件,我们将所有全局中间件放入其中,看起来像这样:

import { CustomServerApp } from './server-types';
import { customMiddleware } from './middlewares/customMiddleware';
export const middlewares = (app: CustomServerApp): void => {
    app.use(
        customMiddleware,
        // maybe more middlewares, etc
    );
}
Run Code Online (Sandbox Code Playgroud)

但是,然后类型检查器运行,我收到如下错误:

No overload matches this call.
  The last overload gave the following error.
    Argument of type '(req: Request, res: Response, next: NextFunction) => void' is not assignable to parameter of type 'PathParams'.
      Type '(req: Request, res: Response, next: NextFunction) => void' is missing the following properties from type '(string | RegExp)[]': pop, push, concat, join, and 27 more.ts(2769)
Run Code Online (Sandbox Code Playgroud)

我一直很难理解为什么这会被最后一个重载定义所困扰。只是基于@types/express,即使类型声明合并,似乎也很难向中间件处理程序添加额外的重载。

即使我遵循与核心表达类型类似的模式来定义中间件处理程序 - https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/express-serve-static-core/index.d.ts# L40-L43 - 它也不起作用。似乎也不容易extend- https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/express/index.d.ts#L99 - 因为你不能将泛型传递给核心 RequestHandler ,与路由器定义 ( IRouterHandler, IRouterMatcher) 不同。当我尝试以这种方式输入时,会遇到不同但相似的类型错误。

有没有其他人经历过做类似的事情?

小智 3

您无法在 req 和 res 变量中添加必填字段,因为 express 无法满足您的约束。此外,express 不处理通过不同中间件后更改 req/res 类型。因此,您的自定义类型可以包含与 ExpressRequest/ExpressResponse 中相同的必填字段,其余字段应该是可选的,并且应该在中间件内进行 nullcheck。

  • 谢谢你的提示,罗马。我会仔细研究这个并报告我的发现。 (3认同)