I'm trying to use TypeScript to it's full potential, so I avoid any
if possible.
I've seen Express routes defined like this:
import { Request, Response } from "express";
myRouter.route("/foo").post((req: Request, res: Response): Response => {
return res.send("Hello World");
});
That works because send()
returns an express Response
.
But if I do a redirect:
myRouter.route("/bar").post((req: Request, res: Response): Response => {
return res.redirect("/baz"); // redirect() returns void!
});
That won't compile because redirect()
returns void, not Response
.
Options:
any
, but I want to avoid that if possibleas unknown as Response
but that seems like a hackWhat is the correct way to declare routes' return types, without using any
?
The problem is that the expected usage based on the current Express typings is different. The expected return types for route handlers and middlewares is void
and Promise<void>
, any other return is not expected.
It should be:
res.send("Hello World");
And in case of an early return:
res.send("Hello World");
return;
The support for Promise<void>
type was added in Express 4 at some point to make it compatible with async
functions, and Express 5 supports rejected promises for error handling.
There is no necessity to specify parameter types when a function is not declared separately, they are inferred. The use of satisfies
type constraint can improve the output of TypeScript errors:
router.post((req, res) => {
res.send("Hello World");
} satisfies RequestHandler);
When a function is declared separately:
const routeHandler: RequestHandler = (req, res, next) => {
res.send("Hello World");
};
And a longer way:
const routeHandler = (req: Request, res: Response, next: NextFunction): void => {
res.send("Hello World");
} satisfies RequestHandler;