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