Careeroza
Extracting Route Params
Parsing a String Type
With infer inside a template literal type you can parse string types. Express, Hono and TanStack Router use this to type route parameters from the path string itself.
Example
type ParamNames<P extends string> =
P extends `${string}:${infer Name}/${infer Rest}` ? Name | ParamNames<Rest>
: P extends `${string}:${infer Name}` ? Name
: never;
type Params<P extends string> = { [K in ParamNames<P>]: string };
function buildPath<P extends string>(pattern: P, params: Params<P>): string {
return pattern.replace(/:(\w+)/g, (_, key: string) => encodeURIComponent((params as Record<string, string>)[key]));
}
const productUrl = buildPath("/products/:id", { id: "42" });
const reviewUrl = buildPath("/shops/:shopId/products/:productId/reviews", { shopId: "s9", productId: "p 1" });
console.log(productUrl);
console.log(reviewUrl);Output
/products/42 /shops/s9/products/p%201/reviews
Missing Param
Example
Forgetting productId is a compile error (TS2345); the parameter list was read from the string.
type ParamNames<P extends string> =
P extends `${string}:${infer Name}/${infer Rest}` ? Name | ParamNames<Rest>
: P extends `${string}:${infer Name}` ? Name
: never;
type Params<P extends string> = { [K in ParamNames<P>]: string };
declare function buildPath<P extends string>(pattern: P, params: Params<P>): string;
buildPath("/shops/:shopId/products/:productId", { shopId: "s9" });Compiler output (tsc)
Line 8: error TS2345: Argument of type '{ shopId: string; }' is not assignable to parameter of type 'Params<"/shops/:shopId/products/:productId">'.
Property 'productId' is missing in type '{ shopId: string; }' but required in type 'Params<"/shops/:shopId/products/:productId">'.