diff --git a/README.md b/README.md
index 077a951..04d1813 100644
--- a/README.md
+++ b/README.md
@@ -60,10 +60,12 @@ You can now import the `getRoute` util from `next-type-safe-routes` and use it t
```ts
import { getRoute } from "next-type-safe-routes";
-// for simple routes
+// for simple routes (e.g. the file `/pages/users.tsx`)
getRoute("/users");
-// for dynamic routes
+// for dynamic routes (e.g. the file `/pages/users/[userId]/index.tsx`)
getRoute({ route: "/users/[userId]", params: { userId: "1" } });
+// for catch all routes (e.g. the file `/pages/catch-all/[[...slug]].tsx`)
+getRoute({ route: "/catch-all", path: "/a/b/c" });
```
Now you just need to decide how you want to integrate `next-type-safe-routes` in your project. If you want inspiration, we demonstrate how to create a simple abstraction for the Next.js `Link` and `router` in [the example project](/example/src).
@@ -99,69 +101,48 @@ How you ensure that only links to existing pages is essentially up to you, but w
A simple method that converts a type-safe route to an "actual" route.
-First, import the method:
+**Examples:**
```ts
import { getRoute } from "next-type-safe-routes";
-```
-
-For simple (non-dynamic) routes, you can simply do:
-
-```ts
-const route = getRoute("/users");
-```
-This will simply return the string `/users`.
+// For simple (non-dynamic) routes
+const route = getRoute("/users"); // => "/users"
-If you need to include a (non-typed) query (or just prefer being more explicit), you can pass an object like so:
-
-```ts
+// With query params
const route = getRoute({
route: "/users",
query: { "not-typed": "whatevs" },
-});
-```
-
-This will return the string `/users?not-typed=whatevs`.
+}); // => "/users?not-typed=whatevs"
-```ts
+// For dynamic routes
const route = getRoute({
route: "/users/[userId]",
params: { userId: 1234 },
-});
+}); // => "/users/1234"
+
+// For catch all routes
+const route = getRoute({
+ route: "/catch-all",
+ path: "/can/be/anything",
+}); // => "/catch-all/can/be/anything"
```
-This will return the string `/users/1234`.
+> [Optional catch all routes](https://nextjs.org/docs/routing/dynamic-routes#optional-catch-all-routes) are also supported.
#### The `getPathname` method
-A simple method that just returns the pathname for a type-safe route.
-
-First, import the method:
+The `getPathname` works similarly to the `getRoute`. It just returs a [Next.js pathname](https://nextjs.org/docs/api-reference/next/router#router-object). For instance:
```ts
import { getPathname } from "next-type-safe-routes";
-```
-
-For simple (non-dynamic) routes, you can simply do:
-
-```ts
-const path = getPathname("/users");
-```
-
-This will return the string `/users`.
-
-And for
-```ts
const path = getPathname({
route: "/users/[userId]",
params: { userId: 1234 },
-});
+}); // => `/users/[userId]`
```
-This will return the string `/users/[userId]`.
-
#### The `TypeSafePage` and `TypeSafeApiRoute` types
These can be useful for making your own abstraction. For instance, if you want to make a tiny abstraction ontop of the `next/router`:
@@ -203,7 +184,18 @@ And for dynamic routes, the type is always:
}
```
-**Example**:
+And for [catch all routes](https://nextjs.org/docs/routing/dynamic-routes#catch-all-routes), a (non-typed) `path` will also be required (or optional for [optional catch all routes](https://nextjs.org/docs/routing/dynamic-routes#optional-catch-all-routes)):
+
+```ts
+{
+ route: string,
+ path: string,
+ params: { ... }, // based on the file name
+ query?: { ... } // any key value pairs (not type-safe)
+}
+```
+
+**Examples**:
```ts
type Query = { [key: string]: any };
@@ -214,6 +206,12 @@ export type TypeSafePage =
route: "/users/[userId]";
params: { userId: string | number };
query?: Query;
+ }
+ | {
+ route: "/users/[userId]/catch-all-route";
+ params: { userId: string | number };
+ path="/catch/all/path"
+ query?: Query;
};
```
diff --git a/example/src/@types/next-type-safe-routes/index.d.ts b/example/src/@types/next-type-safe-routes/index.d.ts
index e89b255..2b380ff 100644
--- a/example/src/@types/next-type-safe-routes/index.d.ts
+++ b/example/src/@types/next-type-safe-routes/index.d.ts
@@ -3,8 +3,8 @@
declare module "next-type-safe-routes" {
type Query = { [key: string]: any };
- export type TypeSafePage = "/" | { route: "/", query?: Query } | { route: "/users/[userId]", params: { userId: string | string[] | number }, query?: Query } | "/users" | { route: "/users", query?: Query };
- export type TypeSafeApiRoute = "/api/mocks" | { route: "/api/mocks", query?: Query } | { route: "/api/users/[userId]", params: { userId: string | string[] | number }, query?: Query } | "/api/users" | { route: "/api/users", query?: Query };
+ export type TypeSafePage = { route: "/catch-all", path: string, query?: Query } | "/" | { route: "/", query?: Query } | { route: "/nested-catch-all/[dynamic]/slugs", path: string, params: { dynamic: string | number }, query?: Query } | "/optional-catch-all" | { route: "/optional-catch-all", path?: string, query?: Query } | { route: "/users/[userId]", params: { userId: string | number }, query?: Query } | "/users" | { route: "/users", query?: Query };
+ export type TypeSafeApiRoute = "/api/mocks" | { route: "/api/mocks", query?: Query } | { route: "/api/users/[userId]", params: { userId: string | number }, query?: Query } | "/api/users" | { route: "/api/users", query?: Query };
export const getPathname = (typeSafeUrl: TypeSafePage | TypeSafeApiRoute) => string;
export const getRoute = (typeSafeUrl: TypeSafePage | TypeSafeApiRoute) => string;
}
diff --git a/example/src/pages/catch-all/[...slug].tsx b/example/src/pages/catch-all/[...slug].tsx
new file mode 100644
index 0000000..391eace
--- /dev/null
+++ b/example/src/pages/catch-all/[...slug].tsx
@@ -0,0 +1,9 @@
+import { useRouter } from "hooks";
+
+const CatchAll = () => {
+ const router = useRouter();
+ const slug = router.query.slug as string[];
+ return