Repository: tatethurston/nextjs-routes
Pull request #196 (2024-09-20 02:39:18)

add next-naviation type helpers


Patch:
diff --git a/README.md b/README.md
index 6b9ce0b..be7e8f0 100644
--- a/README.md
+++ b/README.md
@@ -184,6 +184,8 @@ If you want a type for all possible `pathname`s you can achieve this via `Route`
 
 ```ts
 import type { Route } from "nextjs-routes";
+
+// '/' | '/foos/[foo]' | 'other-route' | ...
 type Pathname = Route["pathname"];
 ```
 
@@ -192,9 +194,17 @@ type Pathname = Route["pathname"];
 If you want to use the generated `Query` for a given `Route`, you can import it from `nextjs-routes`:
 
 ```ts
+// Query | Query & { foo: string } | ...
 import type { RoutedQuery } from "nextjs-routes";
 ```
 
+By default, `query` will be typed as the union of all possible query parameters defined by your application routes. If you'd like to narrow the type to fewer routes or a single page, you can supply the path as a type argument:
+
+```ts
+// Query & { foo: string }
+type FooRouteQuery = RoutedQuery<"/foos/[foo]">;
+```
+
 ### GetServerSidePropsContext
 
 If you're using `getServerSideProps` consider using `GetServerSidePropsContext` from nextjs-routes. This is nearly identical to `GetServerSidePropsContext` from next, but further narrows types based on nextjs-route's route data.
diff --git a/examples/app/@types/nextjs-routes.d.ts b/examples/app/@types/nextjs-routes.d.ts
index 31e93c2..ade9588 100644
--- a/examples/app/@types/nextjs-routes.d.ts
+++ b/examples/app/@types/nextjs-routes.d.ts
@@ -175,3 +175,47 @@ declare module "next/router" {
 
   export function useRouter<P extends Route["pathname"]>(): NextRouter<P>;
 }
+
+// prettier-ignore
+declare module "next/navigation" {
+  export * from "next/dist/client/components/navigation";
+  import type { RoutedQuery, RouteLiteral } from "nextjs-routes";
+
+/**
+ * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
+ * that lets you read the current URL's pathname.
+ *
+ * @example
+ * ```ts
+ * "use client"
+ * import { usePathname } from 'next/navigation'
+ *
+ * export default function Page() {
+ *  const pathname = usePathname() // returns "/dashboard" on /dashboard?foo=bar
+ *  // ...
+ * }
+ * ```
+ *
+ * Read more: [Next.js Docs: `usePathname`](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
+ */
+  export function usePathname(): RouteLiteral;
+
+/**
+ * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
+ * that lets you read a route's dynamic params filled in by the current URL.
+ *
+ * @example
+ * ```ts
+ * "use client"
+ * import { useParams } from 'next/navigation'
+ *
+ * export default function Page() {
+ *   // on /dashboard/[team] where pathname is /dashboard/nextjs
+ *   const { team } = useParams() // team === "nextjs"
+ * }
+ * ```
+ *
+ * Read more: [Next.js Docs: `useParams`](https://nextjs.org/docs/app/api-reference/functions/use-params)
+ */
+  export function useParams<Pathname extends Route["pathname"] = Route["pathname"]>(): RoutedQuery<Pathname>;
+}
diff --git a/packages/nextjs-routes/package.json b/packages/nextjs-routes/package.json
index 82482a7..d878d56 100644
--- a/packages/nextjs-routes/package.json
+++ b/packages/nextjs-routes/package.json
@@ -1,6 +1,6 @@
 {
   "name": "nextjs-routes",
-  "version": "2.2.2-rc.1",
+  "version": "2.2.2-rc.2",
   "description": "Type safe routing for Next.js",
   "license": "MIT",
   "author": "Tate <tatethurston@gmail.com>",
diff --git a/packages/nextjs-routes/src/core.ts b/packages/nextjs-routes/src/core.ts
index b5e451c..ba22232 100644
--- a/packages/nextjs-routes/src/core.ts
+++ b/packages/nextjs-routes/src/core.ts
@@ -94,7 +94,7 @@ function generate(routes: Route[], config: GenerateConfig): string {
     localeDetection: false,
     locales: [],
   };
-  return `\
+  let output = `\
 // THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
 // This file will be automatically regenerated when your Next.js server is running.
 // nextjs-routes version: ${pkg.version}
@@ -313,6 +313,56 @@ declare module "next/router" {
   export function useRouter<P extends Route["pathname"]>(): NextRouter<P>;
 }
 `;
+
+  if (config.usingAppDirectory) {
+    output += `\
+
+// prettier-ignore
+declare module "next/navigation" {
+  export * from "next/dist/client/components/navigation";
+  import type { RoutedQuery, RouteLiteral } from "nextjs-routes";
+
+/**
+ * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
+ * that lets you read the current URL's pathname.
+ *
+ * @example
+ * \`\`\`ts
+ * "use client"
+ * import { usePathname } from 'next/navigation'
+ *
+ * export default function Page() {
+ *  const pathname = usePathname() // returns "/dashboard" on /dashboard?foo=bar
+ *  // ...
+ * }
+ * \`\`\`
+ *
+ * Read more: [Next.js Docs: \`usePathname\`](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
+ */
+  export function usePathname(): RouteLiteral;
+
+/**
+ * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
+ * that lets you read a route's dynamic params filled in by the current URL.
+ *
+ * @example
+ * \`\`\`ts
+ * "use client"
+ * import { useParams } from 'next/navigation'
+ *
+ * export default function Page() {
+ *   // on /dashboard/[team] where pathname is /dashboard/nextjs
+ *   const { team } = useParams() // team === "nextjs"
+ * }
+ * \`\`\`
+ *
+ * Read more: [Next.js Docs: \`useParams\`](https://nextjs.org/docs/app/api-reference/functions/use-params)
+ */
+  export function useParams<Pathname extends Route["pathname"] = Route["pathname"]>(): RoutedQuery<Pathname>;
+}
+`;
+  }
+  return output;
 }
 
 function print(x: unknown, indent: number): string {


Test patch:
diff --git a/packages/nextjs-routes/src/__snapshots__/core.test.ts.snap b/packages/nextjs-routes/src/__snapshots__/core.test.ts.snap
index 6dd63e4..acb09b6 100644
--- a/packages/nextjs-routes/src/__snapshots__/core.test.ts.snap
+++ b/packages/nextjs-routes/src/__snapshots__/core.test.ts.snap
@@ -186,6 +186,50 @@ declare module "next/router" {
 
   export function useRouter<P extends Route["pathname"]>(): NextRouter<P>;
 }
+
+// prettier-ignore
+declare module "next/navigation" {
+  export * from "next/dist/client/components/navigation";
+  import type { RoutedQuery, RouteLiteral } from "nextjs-routes";
+
+/**
+ * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
+ * that lets you read the current URL's pathname.
+ *
+ * @example
+ * \`\`\`ts
+ * "use client"
+ * import { usePathname } from 'next/navigation'
+ *
+ * export default function Page() {
+ *  const pathname = usePathname() // returns "/dashboard" on /dashboard?foo=bar
+ *  // ...
+ * }
+ * \`\`\`
+ *
+ * Read more: [Next.js Docs: \`usePathname\`](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
+ */
+  export function usePathname(): RouteLiteral;
+
+/**
+ * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
+ * that lets you read a route's dynamic params filled in by the current URL.
+ *
+ * @example
+ * \`\`\`ts
+ * "use client"
+ * import { useParams } from 'next/navigation'
+ *
+ * export default function Page() {
+ *   // on /dashboard/[team] where pathname is /dashboard/nextjs
+ *   const { team } = useParams() // team === "nextjs"
+ * }
+ * \`\`\`
+ *
+ * Read more: [Next.js Docs: \`useParams\`](https://nextjs.org/docs/app/api-reference/functions/use-params)
+ */
+  export function useParams<Pathname extends Route["pathname"] = Route["pathname"]>(): RoutedQuery<Pathname>;
+}
 ",
   ],
 ]
@@ -371,6 +415,50 @@ declare module "next/router" {
 
   export function useRouter<P extends Route["pathname"]>(): NextRouter<P>;
 }
+
+// prettier-ignore
+declare module "next/navigation" {
+  export * from "next/dist/client/components/navigation";
+  import type { RoutedQuery, RouteLiteral } from "nextjs-routes";
+
+/**
+ * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
+ * that lets you read the current URL's pathname.
+ *
+ * @example
+ * \`\`\`ts
+ * "use client"
+ * import { usePathname } from 'next/navigation'
+ *
+ * export default function Page() {
+ *  const pathname = usePathname() // returns "/dashboard" on /dashboard?foo=bar
+ *  // ...
+ * }
+ * \`\`\`
+ *
+ * Read more: [Next.js Docs: \`usePathname\`](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
+ */
+  export function usePathname(): RouteLiteral;
+
+/**
+ * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
+ * that lets you read a route's dynamic params filled in by the current URL.
+ *
+ * @example
+ * \`\`\`ts
+ * "use client"
+ * import { useParams } from 'next/navigation'
+ *
+ * export default function Page() {
+ *   // on /dashboard/[team] where pathname is /dashboard/nextjs
+ *   const { team } = useParams() // team === "nextjs"
+ * }
+ * \`\`\`
+ *
+ * Read more: [Next.js Docs: \`useParams\`](https://nextjs.org/docs/app/api-reference/functions/use-params)
+ */
+  export function useParams<Pathname extends Route["pathname"] = Route["pathname"]>(): RoutedQuery<Pathname>;
+}
 ",
   ],
 ]
@@ -1694,6 +1782,50 @@ declare module "next/router" {
 
   export function useRouter<P extends Route["pathname"]>(): NextRouter<P>;
 }
+
+// prettier-ignore
+declare module "next/navigation" {
+  export * from "next/dist/client/components/navigation";
+  import type { RoutedQuery, RouteLiteral } from "nextjs-routes";
+
+/**
+ * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
+ * that lets you read the current URL's pathname.
+ *
+ * @example
+ * \`\`\`ts
+ * "use client"
+ * import { usePathname } from 'next/navigation'
+ *
+ * export default function Page() {
+ *  const pathname = usePathname() // returns "/dashboard" on /dashboard?foo=bar
+ *  // ...
+ * }
+ * \`\`\`
+ *
+ * Read more: [Next.js Docs: \`usePathname\`](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
+ */
+  export function usePathname(): RouteLiteral;
+
+/**
+ * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
+ * that lets you read a route's dynamic params filled in by the current URL.
+ *
+ * @example
+ * \`\`\`ts
+ * "use client"
+ * import { useParams } from 'next/navigation'
+ *
+ * export default function Page() {
+ *   // on /dashboard/[team] where pathname is /dashboard/nextjs
+ *   const { team } = useParams() // team === "nextjs"
+ * }
+ * \`\`\`
+ *
+ * Read more: [Next.js Docs: \`useParams\`](https://nextjs.org/docs/app/api-reference/functions/use-params)
+ */
+  export function useParams<Pathname extends Route["pathname"] = Route["pathname"]>(): RoutedQuery<Pathname>;
+}
 ",
   ],
 ]