Created
April 12, 2022 19:01
-
-
Save lupuszr/5d30efb748217f9f7da802bbd311179f to your computer and use it in GitHub Desktop.
typelevel url parser in typescript
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
type ParamParser<T extends string> = T extends `${infer param}/${infer rest}` ? [param, ...ParamParser<rest>] : [T] | |
type TakeApart<T extends string> = T extends `${infer p}=${infer v}` ? [p, v] : [] | |
type QueryParser<T extends string> = T extends `${infer el}&${infer rest}` ? [TakeApart<el>, ...QueryParser<rest>]: [TakeApart<T>] | |
type urlWithParamAndQuery<T extends string, FB = never> = T extends `${infer Base}/${infer Param}?${infer Query}` ? {base: Base, param: ParamParser<Param>, query: QueryParser<Query>} : FB; | |
type urlWithQuery<T extends string, FB = never> = T extends `${infer Base}?${infer Query}` ? {base: Base, param: [], query: QueryParser<Query>} : FB; | |
type urlWithParam<T extends string, FB = never> = T extends `${infer Base}/${infer Param}` ? {base: Base, param: ParamParser<Param>, query: []} : FB; | |
type staticUrl<T extends string> = {base: T, param: [], query: []}; | |
type url<T extends string> = urlWithParamAndQuery<T, urlWithParam<T, urlWithQuery<T, staticUrl<T>>>>; | |
type Norm<T extends Array<unknown>> = T extends [infer Z, ...infer rest] ? [1, ...Norm<rest>] : []; | |
type And<T extends boolean, K extends boolean> = T extends false ? false : (K extends false ? false : true) | |
type MatchQuery<T, K> = T extends [infer K1, infer V1] ? | |
K extends [infer K2, infer V2] ? | |
K1 extends K2 ? | |
V1 extends V2 ? | |
true: false : false: false: false; | |
type Test1 = MatchQuery<["b", "b"], [string, "b"]> | |
// WIP | |
// type CompareQuery<T, K > = T extends [infer H1, ...infer tail1] ? | |
// K extends [infer H2, ...infer tail2] ? | |
// tail1 extends Array<Array<string>> ? | |
// tail2 extends Array<Array<string>> ? | |
// And<MatchQuery<H1, H2>, CompareQuery<tail1, tail2>> : false : false : false : (T extends [infer H1] ? K extends [infer H2] ? MatchQuery<H1, H2> : H1 : "pina"); | |
//And<MatchQuery<H1, H2>, CompareQuery<tail1, tail2>> | |
// type Test2 = CompareQuery<[["a", "b"], ["c", "d"]], [["a", "b"], ["c", "d"]]> | |
type Match<T extends string, R extends string> = [url<T>["base"] extends url<R>["base"] ? true : false, Norm<url<T>["param"]> extends Norm<url<R>["param"]> ? true : false, Norm<url<T>["query"]> extends Norm<url<R>["query"]> ? true : false]; | |
type CompareRoute<T extends string, R extends string> = Match<T, R> extends [true, true] ? url<R> : never; | |
type Find<Comparator extends string, T extends Array<string>> = T extends [infer Z, ...infer rest] ? | |
Z extends string ? | |
Match<Comparator, Z> extends [true, true, true] ? | |
Z : rest extends Array<string> ? Find<Comparator, rest> : never : never : never; | |
type A = Find<"user/12/aleksa", ["user/12?pina=geci", "user/:userId/:name", "2"]> | |
type ki = CompareRoute<"user/12?name=aleksa", "user/:userId?name=string"> | |
type RoutesGET = [ | |
["user/me", Promise<1337>], | |
["user/:userId?name=string", "this is sparta!!"], | |
["miner/2433", 2000] | |
] | |
type First<T extends Array<unknown>> = T extends [infer H, ...infer tail] ? | |
H extends [infer Fst, infer Snd] ? | |
[Fst, ...First<tail>] : [] : []; | |
type Second<T extends Array<unknown>> = T extends [infer H, ...infer tail] ? | |
H extends [infer Fst, infer Snd] ? | |
[Snd, ...Second<tail>] : [] : []; | |
type FindRouteValue<A extends string, T extends Array<unknown>> = T extends [infer H, ...infer tail] ? | |
H extends [infer Fst, infer Snd] ? | |
Fst extends A ? Snd : FindRouteValue<A, tail> : [] : []; | |
type R = First<RoutesGET>; | |
type Test3 = FindRouteValue<R[2], RoutesGET> | |
function get<T extends string, K = url<Find<T, First<RoutesGET>>>>(r: T): FindRouteValue<Find<T, First<RoutesGET>>, RoutesGET> { | |
throw "Not implemented" | |
} | |
get("user/aleksa?name=Hello") | |
get("user/me") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment