TypeScript: Custom Express Router (TS2769)上的自定义请求类型



我很难让自定义请求类型与TypeScript很好地发挥作用。

在我的应用中有公共和私有路由。

公网路由使用Express中的Request类型。私有路由使用自定义的PrivateRequest类型,扩展了Express的Request类型;它看起来像这样:

import type { Request } from "express";
import type * as Cookies from "cookies";
export type PrivateRequest = Request & {
user: User;
cookies: Cookies;
}

公共和私有路由的路由是这样的:

const publicRouter = express.Router();
const privateRouter = express.Router();
privateRouter.use([userSession]);
publicRouter.post("/login", login);
privateRouter.get("/api/user", user);

下面是一个私有路由的例子,它使用了PrivateRequest类型,这里的TypeScript没有问题。

export default async function user(req: PrivateRequest, res: Response) {
try {
res.json({ test: true });
} catch (err) {
console.error(err);
res.status(500).json({ errors: { server: "Server error" } });
}
}

问题在于私有路由,例如:

privateRouter.get("/api/user", user);
对于私有路由,我从TypeScript得到的具体错误是:

TS2769: No overload匹配此调用

我该如何解决这个问题?我做的每件事都不起作用,我也不完全确定为什么。

如果我在PrivateRequest上使user为空,我可以修复此错误,但这在技术上是不正确的,因为所有的私有路由都作为req对象上的用户得到保证,因为userSession中间件要么响应401,要么将用户添加到req对象以用于后续的私有路由。下面是我的userSession中间件的示例:

export default async function userSession(
req: Request,
res: Response,
next: NextFunction
) {
try {
req.cookies = new Cookies(req, res);
// [...] authentication and user entity fetching (throws if either one fails)
if (user === null) {
res.status(401).json({ errors: { server: "Unauthorised" } });
} else {
// @ts-ignore
req.user = user;
next();
}
} catch {
res.status(401).json({ errors: { server: "Unauthorised" } });
}
}

由于Express的get被定义为接受接受Request而不是PrivateRequest的处理程序,所以你必须向TypeScript保证这是可以的,你知道usercookies将被添加到请求对象中。根据get的定义方式,TypeScript必须假定你的处理程序只会得到一个Request,而不是PrivateRequest

一种方法是使用类型断言,可能是在实用程序函数中:
const addPrivateGet = (path: string, handler: (req: PrivateRequest, res: Response)) => {
privateRouter.get(path, handler as unknown as (req: Request, res: Response) => void);
};
// ...
addPrivateGet("/api/user", user);

另一个选择是在处理程序中使用断言函数:

function assertIsPrivateRequest(req: Request): asserts req is PrivateRequest {
if (!("user" in req)) {
throw new AssertionError(`Invalid request object, missing 'user'`);
}
if (!("cookies" in req)) {
throw new AssertionError(`Invalid request object, missing 'cookies'`);
}
}

然后在处理程序中:

export default async function user(req: Request, res: Response) {
// Note −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^
try {
assertIsPrivateRequest(req); // <==
// You can use `req.user` and `req.cookies` here
res.json({ test: true });
} catch (err) {
console.error(err);
res.status(500).json({ errors: { server: "Server error" } });
}
}

相关内容

  • 没有找到相关文章

最新更新