我很难让自定义请求类型与 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:没有与此调用匹配的过载
我该如何解决这个问题?我尝试的所有方法都不起作用,我不完全确定原因。
如果我在 user
上使 PrivateRequest
可以为空,我可以修复这个错误,但这在技术上是不正确的,因为所有私有路由都被保证为 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" } });
}
}
答案 0 :(得分:1)
由于 Express 的 get
被定义为接受接受 Request
而不是 PrivateRequest
的处理程序,因此您必须向 TypeScript 保证这没问题,您知道 user
并且 cookies
将被添加到请求对象中。 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);
另一种选择是在处理程序中使用 assertion function:
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" } });
}
}