首页 > 解决方案 > typescript 在 checkAuth 中间件之后更改请求的类型

问题描述

我对打字稿很陌生,我遇到了扩展 Request 类型的问题。我实际上找到了一个解决方案,但对我来说感觉不对,而且似乎可能有更好的方法。

第一,结构。我有一个中间件 checkAuth 来检查 Bearer 令牌,在数据库中找到用户(或创建一个,以防这是第一次)并将用户添加到 req 变量。

大多数人建议使用自定义声明修改 Express 的请求类型。我不喜欢这个想法,因为这会将用户对象放入所有请求中,甚至在我实际将用户保存到 req 之前。

另一个解决方案是我现在使用的:

interface ReqWithUser extends Request {
    user?: {
        ...
    }
}

这允许我声明req: ReqWithUser. 但是有一个缺陷。当我尝试访问req.user时,打字稿告诉我它可能是未定义的。嗯,这正是我用user?:. 如果我不在那里打一个问号,那么 typescript 在路由器中很疯狂,说Property 'user' is missing in type Request. 这还算公平。解决方案之一是使用req!.user. 解决了所有问题,但对我来说仍然不完美。我知道它在req.user那里,它不是可选的,否则 checkAuth 将失败并返回 401。如果没有,则用户在那里。感觉正确的解决方案是以某种方式在中间件之后修改 req 类型。checkAuth因为那是用户被添加到请求中的时候。可能吗?

标签: node.jstypescriptexpress

解决方案


该问题与您的类型无关,但事实是 Express 将始终发出Request而不是RequestWithUser.

所以在你的中间件函数中,你总是会得到一个Request. 唯一RequestWithUser可以接受的原因是因为您将其设为可选。

事实是中间件/装饰器模式不适用于express。你有几个选择(你提到的一些)

  1. 使用声明合并来“修补”内置请求。你已经提到你不喜欢这个,因为它有点像黑客。
  2. 不要使用 Express 的中间件系统,而是编写一些了解类型如何随装饰器变化的东西。我不知道这到底是什么样子,或者以前是否已经这样做过。
  3. 每当您想RequestWithUser在控制器/中间件中使用时,请从断言函数开始以确保其user存在(允许您将其设为非可选)。
  4. 在需要时转换为 RequestWithUser。

所有这些选项都有缺点:

  1. 你不喜欢上面提到的原因。它并不总是“准确”的,所以为了方便起见,你有点对 Typescript 撒谎。
  2. 听起来很难做
  3. 需要使用断言函数,这意味着每次要使用用户属性时都需要做一些额外的工作。不需要这项工作,因为作为开发人员知道。
  4. 您可能不喜欢强制转换,原因与您不喜欢使用声明合并的原因相同。

到目前为止,我认为 2 是最好的解决方案,因为它为您提供了打字的优势,无需任何技巧,也无需执行断言函数的额外工作(在运行时发生)。但这意味着放弃 Express 的中间件系统。我不确切知道如何编写这段代码,但我很好奇它是否可以完成......

仅供参考,我打开了另一个堆栈溢出问题,因为我很好奇:

装饰器中间件模式的打字稿


推荐阅读