Last active
June 23, 2024 20:31
-
-
Save fgalassi/1383de81535fd11018f532edd9b7f331 to your computer and use it in GitHub Desktop.
Solution to bonus challenge 1 from https://type-level-typescript.com/members/template-literal-types
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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