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 accepted answer is outdated.
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;