使用 TypeScript 的 Express 路由返回类型

13

我希望充分发挥TypeScript的潜力,因此尽可能避免使用any

我看到过这样定义Express路由的例子:

import { Request, Response } from "express";

myRouter.route("/foo").post((req: Request, res: Response): Response => {
  return res.send("Hello World");
});

那行得通,因为send()返回一个Express Response对象。

但是如果我进行重定向:

myRouter.route("/bar").post((req: Request, res: Response): Response => {
  return res.redirect("/baz");         // redirect() returns void!
});

那个无法编译,因为redirect()返回的是void而不是Response

选项:

  • 简单的解决方法是使路由返回any,但如果可能的话,我想避免这种情况
  • 我看到过一些代码使用as unknown as Response,但那似乎是一种hack方法

如何正确声明路由的返回类型,而不使用any


4
Express框架不关注返回值,因此正确使用它的方式是定义无返回值的回调函数并且不返回任何值。因此,请停止使用return res.send(),而改用res.send()res.redirect()。如果没有返回值且只是想结束函数执行,则不需要使用return,只需使用return;即可。我一直不喜欢return res.send()语法,即使在普通的Javascript中也是如此,因为它暗示着有一个有意义的返回值被返回了,这并不是实际情况。 - jfriend00
@jfriend00,类型声明了一个返回值... 那么你认为是忽略它们并将其声明为 post(...): void 更好吗? - lonix
1
不是这里。这不是关于.post()返回什么的问题,而是关于您传递给它的回调函数返回什么以及如何声明回调函数以匹配它。回调函数应该不返回任何内容。所有.post()做的就是注册回调函数,以便稍后调用,并返回调用它的对象,以便可以链接其他操作。.post()本身在服务器初始化时被调用(以注册路由处理程序),而不是在实际访问路由时调用。传递给.post()的回调函数是作为路由处理程序调用的。 - jfriend00
@jfriend00 哎呀!你说得对!当我创建问题时,我没有粘贴我的真实代码 - 我的处理程序在一个单独的类中,所以它们更容易测试,当我输入上面的内容时,我看错了声明文件。你是对的 - RequestHandler 回调被定义为 (req: Request, res: Response, next: NextFunction): any;... 所以它返回 any,所以我很高兴也这样做。不过,你关于不必要地返回的评论很有帮助(在其他语言中我会这样做)。 - lonix
1
我不是TypeScript专家,所以在这方面没有建议。我不喜欢返回值未被调用者使用的代码(因为我认为这会产生误导性的代码),所以我可能会做一些与此一致的事情。 - jfriend00
显示剩余3条评论
1个回答

26

根据 @jfriend 的评论,回调函数的 RequestHandler声明如下:

(req: Request, res: Response, next: NextFunction): any;

所以在这种情况下使用any是可以的。

然而,声明为void可能会更好,因为Express不期望返回值。这就是我所做的,我认为这里的类型定义是“错误”的(如果不是这种情况并且有一个有效的用例,请告诉我)。


5
"void" 可能是更好的选择,因为它是确切的返回类型。 - udo
6
看起来自那时以来,RequestHandler 的类型已经得到了改进。截至今天,它是(req: Request<P, ResBody, ReqBody, ReqQuery>, res: Response<ResBody>, next: NextFunction): void; - Matt Welke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接