I'm having difficulty getting custom Request types to play nicely with TypeScript.
In my app there are public and private routes.
The public routes use the Request type from Express. The private routes use a custom PrivateRequest type which extends the Request type from Express; which looks like this:
import type { Request } from "express";
import type * as Cookies from "cookies";
export type PrivateRequest = Request & {
user: User;
cookies: Cookies;
}
Routing for the public and private routes looks like this:
const publicRouter = express.Router();
const privateRouter = express.Router();
privateRouter.use([userSession]);
publicRouter.post("/login", login);
privateRouter.get("/api/user", user);
Here's an example of a private route, which makes use of the PrivateRequest type and there are no problems with TypeScript here.
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" } });
}
}
The issue is with the private routes, e.g.:
privateRouter.get("/api/user", user);
The specific error I get back from TypeScript for the privately defined routes is this:
TS2769: No overload matches this call
How can I fix this? Everything I try doesn't work, and I'm not entirely sure why.
I can fix this error if I make user nullable on the PrivateRequest but this is technically incorrect, since all of the private routes are guaranteed as user on the req object since the userSession middleware either responds with a 401 or adds the user to the req object for subsequent private routes. Here's an exmaple of whay my userSession middleware looks like:
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" } });
}
}