Skip to content

Instantly share code, notes, and snippets.

@fgalassi
Last active June 23, 2024 20:31
Show Gist options
  • Save fgalassi/1383de81535fd11018f532edd9b7f331 to your computer and use it in GitHub Desktop.
Save fgalassi/1383de81535fd11018f532edd9b7f331 to your computer and use it in GitHub Desktop.
/**
* The `navigate` function takes a `Path` string that
* can contain parameter names using the `users/:username`
* syntax. Type it so that the `params` object provided
* as the second argument always contains a key for each variable
* in the `Path`.
*/
namespace parseUrlParams {
declare function navigate<U extends string>(
path: U,
params: ParseUrlParams<U>
): void;
// Solution starts here <<<<
type ParseUrlParams<Url extends string> = MapToObject<
FilterStartWith<Split<Url, "/">, ":">
>;
type Split<
Str extends string,
Separator extends string
> = Str extends `${infer Before}${Separator}${infer After}`
? [Before, ...Split<After, Separator>]
: [Str];
type FilterStartWith<
Arr extends string[],
Start extends string
> = Arr extends [infer Head, ...infer Tail extends string[]]
? Head extends `${Start}${infer Name}`
? [Name, ...FilterStartWith<Tail, Start>]
: FilterStartWith<Tail, Start>
: [];
type MapToObject<Props extends string[], Acc = {}> = Props extends [
infer Head extends string,
...infer Tail extends string[]
]
? MapToObject<Tail, Acc & { [Key in Head]: string }>
: Acc;
// Solution ends here <<<<
type res1 = ParseUrlParams<"user/:userId">;
type test1 = Expect<Equal<res1, { userId: string }>>;
type res2 = ParseUrlParams<"user/:userId/dashboard">;
type test2 = Expect<Equal<res2, { userId: string }>>;
type res3 = ParseUrlParams<"user/:userId/dashboard/:dashboardId">;
type test3 = Expect<
Equal<res3, { userId: string } & { dashboardId: string }>
>;
navigate("user/:userId", { userId: "2" }); // ✅
navigate("user/:userId/dashboard", { userId: "2" }); // ✅
// @ts-expect-error ❌ `userId` is missing.
navigate("user/:userId/dashboard/:dashboardId", { dashboardId: "2" });
// ❌
navigate("user/:userId/dashboard/:dashboardId", {
userId: "2",
dashboardId: "2",
// @ts-expect-error
oops: ":(",
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment