node.jstypescriptexpress

How to properly type express route handlers?


New to express, and I'm trying to understand the 'proper' way to have type-safe route handlers. How can I fix this? Clearly my code 'runs', but I'm not sure how to properly type handlers in express. Say I have a route 'events' and some methods:

app.use("/events", eventsRoutes);

within my eventsRoutes I define a simple get, but it has errors in my IDE:

//... 

router.get("/user/:userId", (req, res) => { // <- This is the error
  const { userId } = req.params;
  const collection = EVENTS_COLLECTION.get(userId);
  if (!collection) {
    return res.status(200).json([]);
  }

  // iterate the keys and return an array of events
  const eventsArray: Event[] = [];
  for (const [date, events] of collection.entries()) {
    events.forEach((event) => {
      event.date = new Date(date);
      eventsArray.push(event);
    });
  }

  res.status(200).json(eventsArray);
});

// ...

No overload matches this call. The last overload gave the following error.

Argument of type '(req: Request<{ userId: string; }, any, any, ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>, number>) => Response<...> | undefined' is not assignable to parameter of type 'Application<Record<string, any>>'.
  Type '(req: Request<{ userId: string; }, any, any, ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>, number>) => Response<...> | undefined' is missing the following properties from type 'Application<Record<string, any>>': init, defaultConfiguration, engine, set, and 63 more.

How can I fix this? Clearly my code 'runs', but I'm not sure how to extend or properly 'type' the Request object in express.


Solution

  • This type error means that something else was returned. In this case it should be:

      ...
      if (!collection) {
        res.status(200).json([]);
        return;
      }
      ...
    

    A handler is a a function that returns undefined (void type), or a promise of undefined (Promise<void>) to make it compatible with async functions.

    There is no need to explicitly type a handler, the type is inferred. But it's beneficial to match a type to spot a mistake easier:

    router.get("/user/:userId", (req, res) => {
      ...
    } satisfies RequestHandler);