diff --git a/packages/wouter/src/index.js b/packages/wouter/src/index.js index b5b28ce..7c1bd41 100644 --- a/packages/wouter/src/index.js +++ b/packages/wouter/src/index.js @@ -78,7 +78,7 @@ export const useSearch = () => { return unescape(stripQm(router.searchHook(router))); }; -const matchRoute = (parser, route, path, loose) => { +export const matchRoute = (parser, route, path, loose) => { // if the input is a regexp, skip parsing const { pattern, keys } = route instanceof RegExp diff --git a/packages/wouter/test/match-route.test-d.ts b/packages/wouter/test/match-route.test-d.ts new file mode 100644 index 0000000..c7d1b47 --- /dev/null +++ b/packages/wouter/test/match-route.test-d.ts @@ -0,0 +1,55 @@ +import { it, expectTypeOf, assertType } from "vitest"; +import { matchRoute, useRouter } from "wouter"; + +const { parser } = useRouter(); + +it("should only accept strings", () => { + // @ts-expect-error + assertType(matchRoute(parser, Symbol(), "")); + // @ts-expect-error + assertType(matchRoute(parser, undefined, "")); + assertType(matchRoute(parser, "/", "")); +}); + +it('has a boolean "match" result as a first returned value', () => { + const [match] = matchRoute(parser, "/", ""); + expectTypeOf(match).toEqualTypeOf(); +}); + +it("returns null as parameters when there was no match", () => { + const [match, params] = matchRoute(parser, "/foo", ""); + + if (!match) { + expectTypeOf(params).toEqualTypeOf(); + } +}); + +it("accepts the type of parameters as a generic argument", () => { + const [match, params] = matchRoute<{ id: string; name: string | undefined }>( + parser, + "/app/users/:name?/:id", + "" + ); + + if (match) { + expectTypeOf(params).toEqualTypeOf<{ + id: string; + name: string | undefined; + }>(); + } +}); + +it("infers parameters from the route path", () => { + const [, inferedParams] = matchRoute(parser, "/app/users/:name?/:id/*?", ""); + + if (inferedParams) { + expectTypeOf(inferedParams).toMatchTypeOf<{ + 0?: string; + 1?: string; + 2?: string; + name?: string; + id: string; + wildcard?: string; + }>(); + } +}); diff --git a/packages/wouter/types/index.d.ts b/packages/wouter/types/index.d.ts index 449c133..e1d1704 100644 --- a/packages/wouter/types/index.d.ts +++ b/packages/wouter/types/index.d.ts @@ -25,7 +25,7 @@ import { BrowserSearchHook, } from "./use-browser-location.js"; -import { RouterObject, RouterOptions } from "./router.js"; +import { Parser, RouterObject, RouterOptions } from "./router.js"; // these files only export types, so we can re-export them as-is // in TS 5.0 we'll be able to use `export type * from ...` @@ -191,4 +191,24 @@ export function useParams(): T extends string ? DefaultParams : T; +/* + * Helpers + */ + +export function matchRoute< + T extends DefaultParams | undefined = undefined, + RoutePath extends PathPattern = PathPattern +>( + parser: Parser, + pattern: RoutePath, + path: string, + loose?: boolean +): Match< + T extends DefaultParams + ? T + : RoutePath extends string + ? StringRouteParams + : RegexRouteParams +>; + // tslint:enable:no-unnecessary-generics