I have declared a type for extracting params from url:
type ExtractParams<Path extends string> =
Path extends `${infer Start}/:${infer Param}/${infer Rest}`
? ExtractParams<Start> & ExtractParams<Rest> & { [Key in Param]: string; }
: Path extends `${infer Start}/:${infer Param}`
? ExtractParams<Start> & { [Key in Param]: string }
: {}
code works fine:
type X1 = ExtractParams<'/courses/:courseId/classes/:classId'>
// ^? { classId: string; } & { courseId: string; }
Here is the Playground Link
But there are 2 things that can be improved here:
- Avoid repetition
If you check ExtractParams
type definition, you can see that I have used nested conditions. Outer condition finds Params between /:
and /
. Inner condition finds params at the end of the string. So, I was thinking of declaring /${infer Rest}
as optional somehow. But I don't know how can I declare something as optional in template literal type. Can you please help me to do and explain that?
2. Merge Intersection
The output looks ugly at the moment because each param gets its own object. Is there any way to merge those objects?
Update:
Got an answer for Merging Intersections from this answer: https://stackoverflow.com/a/58965725/2284240
To Merge intersections in my code, I can update it like this:
type Expand<T> = T extends infer U ? { [K in keyof U]: U[K] } : never;
type Params<Path extends string> = Expand<ExtractParams<Path>>;
type X1 = Params<'/courses/:courseId/classes/:classId'>
// ^? { classId: string; courseId: string }
Updated Playground Link
Not posting it as an answer because, I am still in search of a solution to Avoid repetition