Home > front end >  Automatically infer type of req.params when Express request handler is defined outside routing metho
Automatically infer type of req.params when Express request handler is defined outside routing metho

Time:01-18

When I define a request handler inside a call to some Express routing method, Typescript is able to infer the structure of the req.params object from the route:

import express from "express";
let app = express();

app.get("/:abc", (req, res) => {
    // req.params is inferred to be type { abc: string }
    let abc = req.params.abc; // this typechecks - good
    let xyz = req.params.xyz; // this doesn't - good
})

But when I define a request handler outside of the call to the routing method, Express doesn't infer the type:

import express, { RequestHandler } from "express";
let app = express();

let requestHandler: RequestHandler = (req, res) => {
    // req.params is inferred to be type ParamsDictionary
    // which is equal to {[key: string]: string}
    // and thus too generic
    let abc = req.params.abc; // this typechecks - good
    let xyz = req.params.xyz; // this shouldn't, but does - bad
}
app.get("/:abc", requestHandler)

RequestHandler optionally accepts generics to type parts of the request and response, so I can get it to type check the params by explicitly passing a RouteParameters type with the route string:

import express, { RequestHandler } from "express";
import { RouteParameters } from "express-serve-static-core/index.js";
let app = express();

let requestHandler: RequestHandler<RouteParameters<"/:abc">> = (req, res) => {
    // now typescript can infer that req.params is type { abc: string }
    let abc = req.params.abc; // this typechecks - good
    let xyz = req.params.xyz; // this doesn't - good
};
app.get("/:abc", requestHandler);

But this requires me to type the same route twice. This isn't a huge deal, but I don't like that there's no type checking to ensure that the route I pass to the route method is the same as the route I pass to RouteParameters. If I change this code to

let requestHandler: RequestHandler<RouteParameters<"/:abc">> = (req, res) => {
    let abc = req.params.abc; // this typechecks - bad
};
app.get("/:jkl", requestHandler); // changed here

I don't get a type error, which makes sense but is not ideal. Additionally, if I ever wanted to add more type checking to my request handlers by adding additional interfaces, I might have to type the route in more than two places.

Is there any way to get a request handler defined outside of a routing method call to infer the type of req.params, without explicitly passing the RouteParameters<"route-string"> generic type to it?

CodePudding user response:

No, but traditionally what I've done is wrap my dynamic handler function in another one that accepts an app:

import { Express } from "express";

const requestHandlerFor = (app: Express) => app.get("/:abc", ...);

// ...

requestHandlerFor(app);
  • Related