I'm trying to improve types for a frontend route config object. I'm trying to tie the path and prepare fields together so that the prepare function field receives the appropriate parameters based on the :keys in the path.
Each route item in the config (other fields omitted for brevity) looks something like this:
interface Routes<Path extends string> {
path: Path;
prepare?: (params: PathArgs<Path>) => object;
routes?: Routes[];
}
The helpers used to extract the params from the path string are
type PathParams<
Path extends string
> = Path extends `:${infer Param}/${infer Rest}`
? Param | PathParams<Rest>
: Path extends `:${infer Param}`
? Param
: Path extends `${infer _Prefix}:${infer Rest}`
? PathParams<`:${Rest}`>
: never;
type PathArgs<Path extends string> = { [K in PathParams<Path>]: string };
// { siteId: string }
type x = PathArgs<`/dashboard/sites/:siteId`>
Ideally, if I did something like
const routes: Routes[] = [
{
path: `/dashboard/:siteId`,
prepared: (params) => {...},
routes: [
{
path: `/dashboard/:siteId/widgets/:widgetId`,
prepared: (params) => {...}
},
{
path: `/dashboard/:siteId/friend/:friendId`,
prepared: (params) => {...}
}
]
}
]
The type of params would automatically be known to be {siteId: string} in the first route, {siteId: string, widgetId: string} for the second route, and {siteId: string, friendId: string} for the second route.
The type declaration I have above for Routes constrains the path and prepare fields correctly for a single object, but does not handle the recursive nature of the config object where it can be a different generic for each nested route, since each path is unique. I'm wondering if this is possible in TypeScript.
Here is a playground with the above code included