node.jstypescriptexpress

Return type for Express routes with TypeScript


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:

What is the correct way to declare routes' return types, without using any?


Solution

  • 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;