Repository: tatethurston/nextjs-routes
Pull request #201 (2024-09-29 21:00:53)

add useRouter from next/navigation

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/tatethurston/nextjs-routes/pull/201?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tate+Thurston) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 98.10%. Comparing base [(`0956f4f`)](https://app.codecov.io/gh/tatethurston/nextjs-routes/commit/0956f4f33e15abce8674cc7f1d8728bca479d7d5?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tate+Thurston) to head [(`246bc31`)](https://app.codecov.io/gh/tatethurston/nextjs-routes/commit/246bc3186277d43df6510d7d574cc26afad076e7?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tate+Thurston).

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main     #201   +/-   ##
=======================================
  Coverage   98.10%   98.10%           
=======================================
  Files           3        3           
  Lines         158      158           
  Branches       50       50           
=======================================
  Hits          155      155           
  Misses          3        3           
```

| [Flag](https://app.codecov.io/gh/tatethurston/nextjs-routes/pull/201/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tate+Thurston) | Coverage Δ | |
|---|---|---|
| [](https://app.codecov.io/gh/tatethurston/nextjs-routes/pull/201/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tate+Thurston) | `98.10% <ø> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tate+Thurston#carryforward-flags-in-the-pull-request-comment) to find out more.

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/tatethurston/nextjs-routes/pull/201?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tate+Thurston).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tate+Thurston).


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0bcd0be..029a9d7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,13 +17,21 @@
   </Link>;
   ```
 
-- Add `RouteLiteral` type. This type represents a string that confirmed to be a validated application route and can be passed to `Link` or `useRouter`. This is a TypeScript branded type.
+- Add `RouteLiteral` type. This type represents a string that has been confirmed to be a validated application route and can be passed to `Link` or `useRouter`. This is a TypeScript branded type.
 
   ```ts
   import { RouteLiteral } from "nextjs-routes";
   ```
 
-- Refine types for `usePathname` and `useParams` from `"next/navigation"` to use `nextjs-routes` generated types.
+  `route` returns a `RouteLiteral`. If you construct a route string you can cast it to a `RouteLiteral` so that `Link` and `useRouter` will accept it:
+
+  ```
+  const myRoute = `/foos/${foo}` as RouteLiteral
+  ```
+
+  In general, prefer using the `route` helper to generate routes.
+
+- Refine types for `usePathname`, `useRouter` and `useParams` from `"next/navigation"` to use `nextjs-routes` generated types.
 
 - Fix generated routes when using [parallel-routes](https://nextjs.org/docs/app/building-your-application/routing/parallel-routes) and [intercepting-routes](https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes).
 
diff --git a/examples/app/@types/nextjs-routes.d.ts b/examples/app/@types/nextjs-routes.d.ts
index d61e0a2..c014538 100644
--- a/examples/app/@types/nextjs-routes.d.ts
+++ b/examples/app/@types/nextjs-routes.d.ts
@@ -30,7 +30,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -170,7 +170,10 @@ declare module "next/router" {
 // prettier-ignore
 declare module "next/navigation" {
   export * from "next/dist/client/components/navigation";
-  import type { RoutedQuery, RouteLiteral } from "nextjs-routes";
+  import type { Route, RouteLiteral, RoutedQuery } from "nextjs-routes";
+  import type { AppRouterInstance as NextAppRouterInstance, NavigateOptions, PrefetchOptions } from "next/dist/shared/lib/app-router-context.shared-runtime";
+
+  type StaticRoute = Exclude<Route, { query: any }>["pathname"];
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -189,7 +192,33 @@ declare module "next/navigation" {
    *
    * Read more: [Next.js Docs: `usePathname`](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
    */
-  export function usePathname(): RouteLiteral;
+  export const usePathname = () => RouteLiteral;
+
+  type AppRouterInstance = Omit<NextAppRouterInstance, 'push' | 'replace' | 'href'> & {
+    push(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    replace(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    prefetch(href: StaticRoute | RouteLiteral, options?: PrefetchOptions): void;
+  }
+
+  /**
+   *
+   * This hook allows you to programmatically change routes inside [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components).
+   *
+   * @example
+   * ```ts
+   * "use client"
+   * import { useRouter } from 'next/navigation'
+   *
+   * export default function Page() {
+   *  const router = useRouter()
+   *  // ...
+   *  router.push('/dashboard') // Navigate to /dashboard
+   * }
+   * ```
+   *
+   * Read more: [Next.js Docs: `useRouter`](https://nextjs.org/docs/app/api-reference/functions/use-router)
+   */
+  export function useRouter(): AppRouterInstance;
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -208,5 +237,5 @@ declare module "next/navigation" {
    *
    * 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>;
+  export const useParams = <Pathname extends Route["pathname"] = Route["pathname"]>() => RoutedQuery<Pathname>;
 }
diff --git a/examples/app/src/app/client.tsx b/examples/app/src/app/client.tsx
index 8284bb1..fd6f254 100644
--- a/examples/app/src/app/client.tsx
+++ b/examples/app/src/app/client.tsx
@@ -9,7 +9,7 @@ export default function Client() {
   const router = useRouter();
 
   return (
-    <button type="button" onClick={() => router.push("/tate")}>
+    <button type="button" onClick={() => router.push("/")}>
       Dashboard
     </button>
   );
diff --git a/examples/cjs/types/nextjs-routes.d.ts b/examples/cjs/types/nextjs-routes.d.ts
index 54c37cc..fe494da 100644
--- a/examples/cjs/types/nextjs-routes.d.ts
+++ b/examples/cjs/types/nextjs-routes.d.ts
@@ -30,7 +30,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
diff --git a/examples/intl/@types/nextjs-routes.d.ts b/examples/intl/@types/nextjs-routes.d.ts
index 5269920..578f3ca 100644
--- a/examples/intl/@types/nextjs-routes.d.ts
+++ b/examples/intl/@types/nextjs-routes.d.ts
@@ -30,7 +30,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
diff --git a/examples/typescript/types/nextjs-routes.d.ts b/examples/typescript/types/nextjs-routes.d.ts
index aef6fc1..f6c40d6 100644
--- a/examples/typescript/types/nextjs-routes.d.ts
+++ b/examples/typescript/types/nextjs-routes.d.ts
@@ -32,7 +32,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
diff --git a/packages/nextjs-routes/package.json b/packages/nextjs-routes/package.json
index 50fca75..5a55d84 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.4",
+  "version": "2.2.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 b02682c..a595799 100644
--- a/packages/nextjs-routes/src/core.ts
+++ b/packages/nextjs-routes/src/core.ts
@@ -139,7 +139,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -311,7 +311,10 @@ declare module "next/router" {
 // prettier-ignore
 declare module "next/navigation" {
   export * from "next/dist/client/components/navigation";
-  import type { RoutedQuery, RouteLiteral } from "nextjs-routes";
+  import type { Route, RouteLiteral, RoutedQuery } from "nextjs-routes";
+  import type { AppRouterInstance as NextAppRouterInstance, NavigateOptions, PrefetchOptions } from "next/dist/shared/lib/app-router-context.shared-runtime";
+
+  type StaticRoute = Exclude<Route, { query: any }>["pathname"];
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -330,7 +333,33 @@ declare module "next/navigation" {
    *
    * Read more: [Next.js Docs: \`usePathname\`](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
    */
-  export function usePathname(): RouteLiteral;
+  export const usePathname = () => RouteLiteral;
+
+  type AppRouterInstance = Omit<NextAppRouterInstance, 'push' | 'replace' | 'href'> & {
+    push(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    replace(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    prefetch(href: StaticRoute | RouteLiteral, options?: PrefetchOptions): void;
+  }
+
+  /**
+   *
+   * This hook allows you to programmatically change routes inside [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components).
+   *
+   * @example
+   * \`\`\`ts
+   * "use client"
+   * import { useRouter } from 'next/navigation'
+   *
+   * export default function Page() {
+   *  const router = useRouter()
+   *  // ...
+   *  router.push('/dashboard') // Navigate to /dashboard
+   * }
+   * \`\`\`
+   *
+   * Read more: [Next.js Docs: \`useRouter\`](https://nextjs.org/docs/app/api-reference/functions/use-router)
+   */
+  export function useRouter(): AppRouterInstance;
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -349,7 +378,7 @@ declare module "next/navigation" {
    *
    * 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>;
+  export const useParams = <Pathname extends Route["pathname"] = Route["pathname"]>() => RoutedQuery<Pathname>;
 }
 `;
   }


Test patch:
diff --git a/packages/e2e/@types/nextjs-routes.d.ts b/packages/e2e/@types/nextjs-routes.d.ts
index 9dc3e6d..0b81773 100644
--- a/packages/e2e/@types/nextjs-routes.d.ts
+++ b/packages/e2e/@types/nextjs-routes.d.ts
@@ -13,6 +13,7 @@ declare module "nextjs-routes" {
   export type Route =
     | StaticRoute<"/">
     | DynamicRoute<"/[...slug]", { "slug": string[] }>
+    | DynamicRoute<"/bars/[bar]", { "bar": string }>
     | DynamicRoute<"/foos/[foo]", { "foo": string }>;
 
   interface StaticRoute<Pathname> {
@@ -31,7 +32,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -82,14 +83,14 @@ declare module "nextjs-routes" {
 
 // prettier-ignore
 declare module "next/link" {
-  import type { Route } from "nextjs-routes";;
+  import type { Route, RouteLiteral } from "nextjs-routes";;
   import type { LinkProps as NextLinkProps } from "next/dist/client/link";
   import type React from "react";
 
   type StaticRoute = Exclude<Route, { query: any }>["pathname"];
 
   export type LinkProps = Omit<NextLinkProps, "href" | "locale"> & {
-    href: Route | StaticRoute | Omit<Route, "pathname">;
+    href: Route | StaticRoute | Omit<Route, "pathname"> | RouteLiteral;
     locale?: false;
   }
 
@@ -167,3 +168,76 @@ 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 { Route, RouteLiteral, RoutedQuery } from "nextjs-routes";
+  import type { AppRouterInstance as NextAppRouterInstance, NavigateOptions, PrefetchOptions } from "next/dist/shared/lib/app-router-context.shared-runtime";
+
+  type StaticRoute = Exclude<Route, { query: any }>["pathname"];
+
+  /**
+   * 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 const usePathname = () => RouteLiteral;
+
+  type AppRouterInstance = Omit<NextAppRouterInstance, 'push' | 'replace' | 'href'> & {
+    push(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    replace(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    prefetch(href: StaticRoute | RouteLiteral, options?: PrefetchOptions): void;
+  }
+
+  /**
+   *
+   * This hook allows you to programmatically change routes inside [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components).
+   *
+   * @example
+   * ```ts
+   * "use client"
+   * import { useRouter } from 'next/navigation'
+   *
+   * export default function Page() {
+   *  const router = useRouter()
+   *  // ...
+   *  router.push('/dashboard') // Navigate to /dashboard
+   * }
+   * ```
+   *
+   * Read more: [Next.js Docs: `useRouter`](https://nextjs.org/docs/app/api-reference/functions/use-router)
+   */
+  export function useRouter(): AppRouterInstance;
+
+  /**
+   * 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 const useParams = <Pathname extends Route["pathname"] = Route["pathname"]>() => RoutedQuery<Pathname>;
+}
diff --git a/packages/e2e/app/bars/[bar]/page.tsx b/packages/e2e/app/bars/[bar]/page.tsx
new file mode 100644
index 0000000..34be283
--- /dev/null
+++ b/packages/e2e/app/bars/[bar]/page.tsx
@@ -0,0 +1,1 @@
+export default () => <div>Bar</div>;
diff --git a/packages/e2e/app/layout.tsx b/packages/e2e/app/layout.tsx
new file mode 100644
index 0000000..9a40bcd
--- /dev/null
+++ b/packages/e2e/app/layout.tsx
@@ -0,0 +1,12 @@
+export default function RootLayout({
+  children,
+}: {
+  children: React.ReactNode;
+}) {
+  return (
+    <html>
+      <head />
+      <body>{children}</body>
+    </html>
+  );
+}
diff --git a/packages/e2e/next-env.d.ts b/packages/e2e/next-env.d.ts
index a4a7b3f..725dd6f 100644
--- a/packages/e2e/next-env.d.ts
+++ b/packages/e2e/next-env.d.ts
@@ -1,5 +1,6 @@
 /// <reference types="next" />
 /// <reference types="next/image-types/global" />
+/// <reference types="next/navigation-types/compat/navigation" />
 
 // NOTE: This file should not be edited
-// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
+// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
diff --git a/packages/e2e/tsconfig.json b/packages/e2e/tsconfig.json
index 99710e8..6ef5cd5 100644
--- a/packages/e2e/tsconfig.json
+++ b/packages/e2e/tsconfig.json
@@ -13,8 +13,13 @@
     "resolveJsonModule": true,
     "isolatedModules": true,
     "jsx": "preserve",
-    "incremental": true
+    "incremental": true,
+    "plugins": [
+      {
+        "name": "next"
+      }
+    ]
   },
-  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
+  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
   "exclude": ["node_modules"]
 }
diff --git a/packages/e2e/typetest.tsx b/packages/e2e/typetest.tsx
index b59e450..76ad937 100644
--- a/packages/e2e/typetest.tsx
+++ b/packages/e2e/typetest.tsx
@@ -1,12 +1,18 @@
 import Link from "next/link";
 import { LinkProps } from "next/link";
 import { useRouter, RouterEvent, NextRouter } from "next/router";
+import {
+  usePathname,
+  useRouter as useAppRouter,
+  useParams,
+} from "next/navigation";
 import {
   route,
   type Route,
   type RoutedQuery,
   type GetServerSideProps,
   type GetServerSidePropsContext,
+  RouteLiteral,
 } from "nextjs-routes";
 import nextRoutes from "nextjs-routes/config";
 
@@ -100,11 +106,11 @@ const router = useRouter();
 
 // pathname
 
-expectType<"/" | "/foos/[foo]" | "/[...slug]">(router.pathname);
+expectType<"/" | "/foos/[foo]" | "/bars/[bar]" | "/[...slug]">(router.pathname);
 
 // route
 
-expectType<"/" | "/foos/[foo]" | "/[...slug]">(router.route);
+expectType<"/" | "/foos/[foo]" | "/bars/[bar]" | "/[...slug]">(router.route);
 
 // query
 
@@ -316,3 +322,35 @@ getServerSideProps = (async (ctx) => {
     },
   };
 }) satisfies GetServerSideProps<{}, "/foos/[foo]">;
+
+// next/navigation
+interface NavigateOptions {
+  scroll?: boolean;
+}
+
+enum PrefetchKind {
+  AUTO = "auto",
+  FULL = "full",
+  TEMPORARY = "temporary",
+}
+
+interface PrefetchOptions {
+  kind: PrefetchKind;
+}
+expectType<() => void>(useAppRouter().back);
+expectType<() => void>(useAppRouter().forward);
+expectType<() => void>(useAppRouter().refresh);
+expectType<(href: RouteLiteral, options: NavigateOptions) => void>(
+  useAppRouter().push,
+);
+expectType<(href: RouteLiteral, options: NavigateOptions) => void>(
+  useAppRouter().replace,
+);
+expectType<(href: string, options: PrefetchOptions) => void>(
+  useAppRouter().prefetch,
+);
+
+expectType<RouteLiteral>(usePathname());
+
+expectType<RoutedQuery>(useParams());
+expectType<RoutedQuery<"/bars/[bar]">>(useParams<"/bars/[bar]">());
diff --git a/packages/nextjs-routes/src/__snapshots__/core.test.ts.snap b/packages/nextjs-routes/src/__snapshots__/core.test.ts.snap
index 32cc04d..4eedbb9 100644
--- a/packages/nextjs-routes/src/__snapshots__/core.test.ts.snap
+++ b/packages/nextjs-routes/src/__snapshots__/core.test.ts.snap
@@ -41,7 +41,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -181,7 +181,10 @@ declare module "next/router" {
 // prettier-ignore
 declare module "next/navigation" {
   export * from "next/dist/client/components/navigation";
-  import type { RoutedQuery, RouteLiteral } from "nextjs-routes";
+  import type { Route, RouteLiteral, RoutedQuery } from "nextjs-routes";
+  import type { AppRouterInstance as NextAppRouterInstance, NavigateOptions, PrefetchOptions } from "next/dist/shared/lib/app-router-context.shared-runtime";
+
+  type StaticRoute = Exclude<Route, { query: any }>["pathname"];
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -200,7 +203,33 @@ declare module "next/navigation" {
    *
    * Read more: [Next.js Docs: \`usePathname\`](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
    */
-  export function usePathname(): RouteLiteral;
+  export const usePathname = () => RouteLiteral;
+
+  type AppRouterInstance = Omit<NextAppRouterInstance, 'push' | 'replace' | 'href'> & {
+    push(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    replace(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    prefetch(href: StaticRoute | RouteLiteral, options?: PrefetchOptions): void;
+  }
+
+  /**
+   *
+   * This hook allows you to programmatically change routes inside [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components).
+   *
+   * @example
+   * \`\`\`ts
+   * "use client"
+   * import { useRouter } from 'next/navigation'
+   *
+   * export default function Page() {
+   *  const router = useRouter()
+   *  // ...
+   *  router.push('/dashboard') // Navigate to /dashboard
+   * }
+   * \`\`\`
+   *
+   * Read more: [Next.js Docs: \`useRouter\`](https://nextjs.org/docs/app/api-reference/functions/use-router)
+   */
+  export function useRouter(): AppRouterInstance;
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -219,7 +248,7 @@ declare module "next/navigation" {
    *
    * 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>;
+  export const useParams = <Pathname extends Route["pathname"] = Route["pathname"]>() => RoutedQuery<Pathname>;
 }
 ",
   ],
@@ -261,7 +290,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -401,7 +430,10 @@ declare module "next/router" {
 // prettier-ignore
 declare module "next/navigation" {
   export * from "next/dist/client/components/navigation";
-  import type { RoutedQuery, RouteLiteral } from "nextjs-routes";
+  import type { Route, RouteLiteral, RoutedQuery } from "nextjs-routes";
+  import type { AppRouterInstance as NextAppRouterInstance, NavigateOptions, PrefetchOptions } from "next/dist/shared/lib/app-router-context.shared-runtime";
+
+  type StaticRoute = Exclude<Route, { query: any }>["pathname"];
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -420,7 +452,33 @@ declare module "next/navigation" {
    *
    * Read more: [Next.js Docs: \`usePathname\`](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
    */
-  export function usePathname(): RouteLiteral;
+  export const usePathname = () => RouteLiteral;
+
+  type AppRouterInstance = Omit<NextAppRouterInstance, 'push' | 'replace' | 'href'> & {
+    push(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    replace(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    prefetch(href: StaticRoute | RouteLiteral, options?: PrefetchOptions): void;
+  }
+
+  /**
+   *
+   * This hook allows you to programmatically change routes inside [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components).
+   *
+   * @example
+   * \`\`\`ts
+   * "use client"
+   * import { useRouter } from 'next/navigation'
+   *
+   * export default function Page() {
+   *  const router = useRouter()
+   *  // ...
+   *  router.push('/dashboard') // Navigate to /dashboard
+   * }
+   * \`\`\`
+   *
+   * Read more: [Next.js Docs: \`useRouter\`](https://nextjs.org/docs/app/api-reference/functions/use-router)
+   */
+  export function useRouter(): AppRouterInstance;
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -439,7 +497,7 @@ declare module "next/navigation" {
    *
    * 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>;
+  export const useParams = <Pathname extends Route["pathname"] = Route["pathname"]>() => RoutedQuery<Pathname>;
 }
 ",
   ],
@@ -482,7 +540,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -622,7 +680,10 @@ declare module "next/router" {
 // prettier-ignore
 declare module "next/navigation" {
   export * from "next/dist/client/components/navigation";
-  import type { RoutedQuery, RouteLiteral } from "nextjs-routes";
+  import type { Route, RouteLiteral, RoutedQuery } from "nextjs-routes";
+  import type { AppRouterInstance as NextAppRouterInstance, NavigateOptions, PrefetchOptions } from "next/dist/shared/lib/app-router-context.shared-runtime";
+
+  type StaticRoute = Exclude<Route, { query: any }>["pathname"];
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -641,7 +702,33 @@ declare module "next/navigation" {
    *
    * Read more: [Next.js Docs: \`usePathname\`](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
    */
-  export function usePathname(): RouteLiteral;
+  export const usePathname = () => RouteLiteral;
+
+  type AppRouterInstance = Omit<NextAppRouterInstance, 'push' | 'replace' | 'href'> & {
+    push(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    replace(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    prefetch(href: StaticRoute | RouteLiteral, options?: PrefetchOptions): void;
+  }
+
+  /**
+   *
+   * This hook allows you to programmatically change routes inside [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components).
+   *
+   * @example
+   * \`\`\`ts
+   * "use client"
+   * import { useRouter } from 'next/navigation'
+   *
+   * export default function Page() {
+   *  const router = useRouter()
+   *  // ...
+   *  router.push('/dashboard') // Navigate to /dashboard
+   * }
+   * \`\`\`
+   *
+   * Read more: [Next.js Docs: \`useRouter\`](https://nextjs.org/docs/app/api-reference/functions/use-router)
+   */
+  export function useRouter(): AppRouterInstance;
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -660,7 +747,7 @@ declare module "next/navigation" {
    *
    * 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>;
+  export const useParams = <Pathname extends Route["pathname"] = Route["pathname"]>() => RoutedQuery<Pathname>;
 }
 ",
   ],
@@ -702,7 +789,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -842,7 +929,10 @@ declare module "next/router" {
 // prettier-ignore
 declare module "next/navigation" {
   export * from "next/dist/client/components/navigation";
-  import type { RoutedQuery, RouteLiteral } from "nextjs-routes";
+  import type { Route, RouteLiteral, RoutedQuery } from "nextjs-routes";
+  import type { AppRouterInstance as NextAppRouterInstance, NavigateOptions, PrefetchOptions } from "next/dist/shared/lib/app-router-context.shared-runtime";
+
+  type StaticRoute = Exclude<Route, { query: any }>["pathname"];
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -861,7 +951,33 @@ declare module "next/navigation" {
    *
    * Read more: [Next.js Docs: \`usePathname\`](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
    */
-  export function usePathname(): RouteLiteral;
+  export const usePathname = () => RouteLiteral;
+
+  type AppRouterInstance = Omit<NextAppRouterInstance, 'push' | 'replace' | 'href'> & {
+    push(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    replace(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    prefetch(href: StaticRoute | RouteLiteral, options?: PrefetchOptions): void;
+  }
+
+  /**
+   *
+   * This hook allows you to programmatically change routes inside [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components).
+   *
+   * @example
+   * \`\`\`ts
+   * "use client"
+   * import { useRouter } from 'next/navigation'
+   *
+   * export default function Page() {
+   *  const router = useRouter()
+   *  // ...
+   *  router.push('/dashboard') // Navigate to /dashboard
+   * }
+   * \`\`\`
+   *
+   * Read more: [Next.js Docs: \`useRouter\`](https://nextjs.org/docs/app/api-reference/functions/use-router)
+   */
+  export function useRouter(): AppRouterInstance;
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -880,7 +996,7 @@ declare module "next/navigation" {
    *
    * 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>;
+  export const useParams = <Pathname extends Route["pathname"] = Route["pathname"]>() => RoutedQuery<Pathname>;
 }
 ",
   ],
@@ -922,7 +1038,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -1122,7 +1238,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -1300,7 +1416,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -1476,7 +1592,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -1652,7 +1768,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -1828,7 +1944,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -2006,7 +2122,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -2146,7 +2262,10 @@ declare module "next/router" {
 // prettier-ignore
 declare module "next/navigation" {
   export * from "next/dist/client/components/navigation";
-  import type { RoutedQuery, RouteLiteral } from "nextjs-routes";
+  import type { Route, RouteLiteral, RoutedQuery } from "nextjs-routes";
+  import type { AppRouterInstance as NextAppRouterInstance, NavigateOptions, PrefetchOptions } from "next/dist/shared/lib/app-router-context.shared-runtime";
+
+  type StaticRoute = Exclude<Route, { query: any }>["pathname"];
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -2165,7 +2284,33 @@ declare module "next/navigation" {
    *
    * Read more: [Next.js Docs: \`usePathname\`](https://nextjs.org/docs/app/api-reference/functions/use-pathname)
    */
-  export function usePathname(): RouteLiteral;
+  export const usePathname = () => RouteLiteral;
+
+  type AppRouterInstance = Omit<NextAppRouterInstance, 'push' | 'replace' | 'href'> & {
+    push(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    replace(href: StaticRoute | RouteLiteral, options?: NavigateOptions): void;
+    prefetch(href: StaticRoute | RouteLiteral, options?: PrefetchOptions): void;
+  }
+
+  /**
+   *
+   * This hook allows you to programmatically change routes inside [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components).
+   *
+   * @example
+   * \`\`\`ts
+   * "use client"
+   * import { useRouter } from 'next/navigation'
+   *
+   * export default function Page() {
+   *  const router = useRouter()
+   *  // ...
+   *  router.push('/dashboard') // Navigate to /dashboard
+   * }
+   * \`\`\`
+   *
+   * Read more: [Next.js Docs: \`useRouter\`](https://nextjs.org/docs/app/api-reference/functions/use-router)
+   */
+  export function useRouter(): AppRouterInstance;
 
   /**
    * A [Client Component](https://nextjs.org/docs/app/building-your-application/rendering/client-components) hook
@@ -2184,7 +2329,7 @@ declare module "next/navigation" {
    *
    * 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>;
+  export const useParams = <Pathname extends Route["pathname"] = Route["pathname"]>() => RoutedQuery<Pathname>;
 }
 ",
   ],
@@ -2226,7 +2371,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];
@@ -2419,7 +2564,7 @@ declare module "nextjs-routes" {
     [key: string]: string | string[] | undefined;
   };
 
-  export type RoutedQuery<P extends Route["pathname"]> = Extract<
+  export type RoutedQuery<P extends Route["pathname"] = Route["pathname"]> = Extract<
     Route,
     { pathname: P }
   >["query"];