Skip to content

Commit

Permalink
feat(router): add wildcard support to req.params type-safety (#17)
Browse files Browse the repository at this point in the history
* feat(router): add wildcard to string patterns
* chore: swap merge order
* chore: add type-check assertions

Related #16
Co-authored-by: Luke Edwards <luke.edwards05@gmail.com>
  • Loading branch information
dummdidumm committed Mar 25, 2021
1 parent b048388 commit fbf6e48
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 8 deletions.
17 changes: 10 additions & 7 deletions src/router.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,20 @@ export function listen(handler: ResponseHandler): void;
export type Route = { params: Params; handler: Handler | false };
export type Handler<P extends Params = Params> = (req: ServerRequest<P>, res: ServerResponse) => Promisable<Response|void>;

// TODO: wildcard
export type RouteParams<T extends string> =
T extends `${infer S}:${infer P}?/${infer Rest}`
T extends `${infer Prev}/*/${infer Rest}`
? RouteParams<Prev> & { wild: string } & RouteParams<Rest>
: T extends `${string}:${infer P}?/${infer Rest}`
? { [K in P]?: string } & RouteParams<Rest>
: T extends `${infer S}:${infer P}/${infer Rest}`
? { [K in P | keyof RouteParams<Rest>]: string }
: T extends `${infer S}:${infer P}?`
: T extends `${string}:${infer P}/${infer Rest}`
? { [K in P]: string } & RouteParams<Rest>
: T extends `${string}:${infer P}?`
? { [K in P]?: string }
: T extends `${infer S}:${infer P}`
: T extends `${string}:${infer P}`
? { [K in P]: string }
: {};
: T extends `${string}*`
? { wild: string }
: {};

export declare class Router {
add<T extends RegExp>(method: string, route: T, handler: Handler<Params>): void;
Expand Down
41 changes: 40 additions & 1 deletion types/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ Cache.listen(API.run);
* > PATTERNS & PARAMS
*/

let foo='', bar='';
let foo='', bar='', baz='', wild='';

// @ts-expect-error
assert<RouteParams<'/:foo'>>({ /*empty*/ });
Expand Down Expand Up @@ -253,6 +253,34 @@ assert<RouteParams<'/:foo?/baz/:bar?'>>({ /*empty*/ });
assert<RouteParams<'/:foo?/baz/:bar?'>>({ foo, bar });
assert<RouteParams<'/:foo?/baz/:bar?'>>({ bar });

// @ts-expect-error
assert<RouteParams<'/*'>>({ bar });
assert<RouteParams<'/*'>>({ wild });
// @ts-expect-error
assert<RouteParams<'/foo/*'>>({ /*empty*/ });
assert<RouteParams<'/foo/*'>>({ wild });
// @ts-expect-error
assert<RouteParams<'/:foo/*'>>({ foo });
assert<RouteParams<'/:foo/*'>>({ foo, wild });
// @ts-expect-error
assert<RouteParams<'/:foo?/*'>>({ /*empty*/ });
assert<RouteParams<'/:foo?/*'>>({ foo, wild });
assert<RouteParams<'/:foo?/*'>>({ wild });
// @ts-expect-error
assert<RouteParams<'/:foo/*/:bar?'>>({ bar, wild});
assert<RouteParams<'/:foo/*/:bar?'>>({ foo, bar, wild});
// @ts-expect-error
assert<RouteParams<'/:foo/*/:bar/:baz?'>>({ foo, bar, baz });
assert<RouteParams<'/:foo/*/:bar/:baz?'>>({ foo, bar, baz, wild });
// @ts-expect-error
assert<RouteParams<'/:foo/*/:bar?/:baz'>>({ foo, baz });
assert<RouteParams<'/:foo/*/:bar?/:baz'>>({ foo, baz, wild });
assert<RouteParams<'/:foo/*/:bar?/:baz'>>({ foo, bar, baz, wild });
// @ts-expect-error
assert<RouteParams<'/:foo?/*/:bar/:baz'>>({ bar, baz });
assert<RouteParams<'/:foo?/*/:bar/:baz'>>({ bar, baz, wild });
assert<RouteParams<'/:foo?/*/:bar/:baz'>>({ foo, bar, baz, wild });

API.add('GET', '/foo', (req) => {
assert<{}>(req.params);
// @ts-expect-error
Expand All @@ -276,6 +304,17 @@ API.add('GET', '/foo/:bar?/:baz', (req) => {
req.params.hello;
});

API.add('GET', '/foo/:bar?/*/:baz', (req) => {
assert<{ bar?: string, baz: string, wild: string }>(req.params);
assert<string|undefined>(req.params.bar);
assert<string>(req.params.wild);
assert<string>(req.params.baz);
// @ts-expect-error
assert<string>(req.params.bar);
// @ts-expect-error
req.params.hello;
});

API.add('GET', /^[/]foobar[/]?/, (req) => {
assert<{}>(req.params);
assert<Params>(req.params);
Expand Down

0 comments on commit fbf6e48

Please sign in to comment.