My goal is to enhance the types for a frontend route configuration object by linking the `path` and `prepare` fields together. This way, the `prepare` function field will receive the appropriate parameters based on the `:keys` in the path.
Each route item in the configuration (other fields excluded for brevity) appears as follows:
interface Routes<Path extends string> {
path: Path;
prepare?: (params: PathArgs<Path>) => object;
routes?: Routes[];
}
The utilities used to extract the parameters 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 define 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` should automatically be known as `{siteId: string}` in the first route, `{siteId: string, widgetId: string}` in the second route, and `{siteId: string, friendId: string}` in the third route.
The type declaration above for `Routes` correctly constrains the path and prepare fields for a single object but does not handle the recursive nature of the configuration object, where each nested route can have a different generic since each path is unique. I am curious about whether this is achievable in TypeScript.
Here is a playground with the above code included