I’m trying to build a recursive type in TypeScript that will resolve each possible route path, including nested paths, from a given route configuration. However, I’m encountering issues with type constraints and inference.
I have defined the routes using a TypedRoute interface and a createRoute function:
interface TypedRoute<
Path extends string,
QueryParams extends Record<string, string> = {}
> {
path: Path;
queryParams?: QueryParams;
children?: TypedRoute<any, any>[];
}
function createRoute<
Path extends string,
QueryParams extends Record<string, string> = {}
>(config: TypedRoute<Path, QueryParams>) {
return config;
}
const routes = [
createRoute({
path: 'results/:id/foo/:bar'
}),
createRoute({
path: 'home',
children: [
createRoute({
path: 'bar',
children: [
createRoute({ path: 'baz' })
]
}),
],
}),
]
Now, I’m trying to create a type ExtractRoutePaths that recursively extracts all possible paths:
type ExtractRoutePaths<T extends readonly TypedRoute<any, any>[]> =
T extends readonly []
? never
: T extends readonly [infer First, ...infer Rest]
? First extends TypedRoute<infer P, any>
? First extends { children: infer C }
? C extends readonly TypedRoute<any, any>[]
? `{P}` | ExtractRoutePaths<C, `${P}/`> | ExtractRoutePaths<Rest extends readonly TypedRoute<any, any>[] ? Rest : never>
: `${P}` | ExtractRoutePaths<Rest extends readonly TypedRoute<any, any>[] ? Rest : never>
: `${P}` | ExtractRoutePaths<Rest extends readonly TypedRoute<any, any>[] ? Rest : never>
: ExtractRoutePaths<Rest extends readonly TypedRoute<any, any>[] ? Rest : never>
: never;
I expect the Routes to be:
results/:id/foo/:bar | home | home/bar | home/bar/baz
What am I doing wrong, and how can I correctly build this recursive type to extract all possible paths, including nested ones?