node.js - 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
因为那是用户被添加到请求中的时候。可能吗?
解决方案
该问题与您的类型无关,但事实是 Express 将始终发出Request
而不是RequestWithUser
.
所以在你的中间件函数中,你总是会得到一个Request
. 唯一RequestWithUser
可以接受的原因是因为您将其设为可选。
事实是中间件/装饰器模式不适用于express。你有几个选择(你提到的一些)
- 使用声明合并来“修补”内置请求。你已经提到你不喜欢这个,因为它有点像黑客。
- 不要使用 Express 的中间件系统,而是编写一些了解类型如何随装饰器变化的东西。我不知道这到底是什么样子,或者以前是否已经这样做过。
- 每当您想
RequestWithUser
在控制器/中间件中使用时,请从断言函数开始以确保其user
存在(允许您将其设为非可选)。 - 在需要时转换为 RequestWithUser。
所有这些选项都有缺点:
- 你不喜欢上面提到的原因。它并不总是“准确”的,所以为了方便起见,你有点对 Typescript 撒谎。
- 听起来很难做
- 需要使用断言函数,这意味着每次要使用用户属性时都需要做一些额外的工作。不需要这项工作,因为您作为开发人员知道。
- 您可能不喜欢强制转换,原因与您不喜欢使用声明合并的原因相同。
到目前为止,我认为 2 是最好的解决方案,因为它为您提供了打字的优势,无需任何技巧,也无需执行断言函数的额外工作(在运行时发生)。但这意味着放弃 Express 的中间件系统。我不确切知道如何编写这段代码,但我很好奇它是否可以完成......
仅供参考,我打开了另一个堆栈溢出问题,因为我很好奇:
推荐阅读
- java - 提取查询结果的问题
- python - 无法通过硒打开铬
- pandas - 将 6 位 int 转换为 pandas 中的 yyyymm
- python - 在深度 div 树中使用 beautifulsoup 提取属性失败
- sql - 将两个表连接到另一个表中未找到的数据
- algorithm - 覆盖图中所有节点所需的最少摄像机数量
- node.js - 使用节点 js/firebase 后端制作 xamarin 表单应用程序(ios 和 android),但无法弄清楚如何将客户端附加到后端
- c# - 从 SQL 表填充 DataGridView 数据并从不同的 SQL Server 表填充 GridView ComboBox
- code-signing - STATUS_NOT_FOUND 为 signtool.exe 中的“意外内部错误”
- c - 在C中使用ncurses的wrefresh函数时出现分段错误