在打字稿中扩展 express.Request

时间:2021-05-20 20:57:12

标签: node.js typescript express

我可以在打字稿中轻松扩展 express.Request,例如:

interface MyRequest extends express.Request {
    userId: string;
}

但是,如果我编写一个使用它的中间件函数,例如:

const myMiddlewareFn = (req: MyRequest, res: express.Response) => {
    req.userId; // <-- this works as a string
}
app.get('/user', myMiddlewareFn) // <-- this does NOT type-check because MyRequest is more narrow than express.Request.

我看到很多关于如何扩展 express.Request 的讨论。我怎样才能在我的路线中正确地进行类型检查?

目前我正在做这样的事情:

/**
 * @param allowedRoles see HasuraCustomClaims
 * @param handlerFn the final business logic
 * @returns an array of middleware, correctly typed for the handlerFn
 */
export function addApiAuthMiddleware(
    allowedRoles: string[],
    ...handlerFns: (
        | ((req: OTApiAuthorizedRequest, res: Response) => Promise<void>)
        | ((req: OTApiValidatedAndAuthorizedRequest<any>, res: Response) => Promise<void>)
    )[]
): express.RequestHandler[] {
    return [
        decodeIdToken,
        guardRequestHandler(createRoleAuthMiddleware(allowedRoles)),
        ...handlerFns.map((handlerFn) => guardRequestHandler(handlerFn)),
    ];
}

/**
 * This typecasting is a *little* jank.
 *
 * @param middlewareOrHandlerFn either api middleware or a final api handler function
 * @returns
 */
export function guardRequestHandler<T extends Request>(
    middlewareOrHandlerFn:
        | ((req: T, res: Response, next: express.NextFunction) => Promise<void>)
        | ((req: T, res: Response) => Promise<void>),
): express.RequestHandler {
    return (middlewareOrHandlerFn as unknown) as express.RequestHandler;
}

// this below type-checks
app.get('/user', ...addApiAuthMiddleware(['admin'], userHandlerFn));

有更好的方法吗?

2 个答案:

答案 0 :(得分:0)

您可以将 app.get('/user', myMiddlewareFn) 更改为 app.get('/user', myMiddlewareFn as any)app .get('/user', myMiddlewareFn) 这些是相同的,并且都是编译时转换不是运行时

答案 1 :(得分:0)

设置您的自定义属性是可选属性。

interface MyRequest extends express.Request {
    userId?: string; // userId is optional
}

在您的中间件或请求处理程序中,您始终需要确保 userId 不是未定义的。

const myMiddlewareFn = (req: MyRequest, res: express.Response) => { // missing next function ?
    if (req.userId) {
        // do something with userId
        req.userId; // <-- this works as a string
    }
}