From b3aad7075360a53e222ec83deecf3ef9c7e784ba Mon Sep 17 00:00:00 2001 From: Tate Thurston Date: Sun, 29 Sep 2024 13:58:32 -0700 Subject: [PATCH] add useRouter from next/navigation --- CHANGELOG.md | 12 +- examples/app/@types/nextjs-routes.d.ts | 37 +++- examples/cjs/types/nextjs-routes.d.ts | 2 +- examples/intl/@types/nextjs-routes.d.ts | 2 +- examples/typescript/types/nextjs-routes.d.ts | 2 +- packages/e2e/@types/nextjs-routes.d.ts | 80 ++++++- packages/e2e/app/bars/[bar]/page.tsx | 1 + packages/e2e/app/layout.tsx | 12 ++ packages/e2e/next-env.d.ts | 3 +- packages/e2e/tsconfig.json | 9 +- packages/e2e/typetest.tsx | 42 +++- packages/nextjs-routes/package.json | 2 +- .../src/__snapshots__/core.test.ts.snap | 201 +++++++++++++++--- packages/nextjs-routes/src/core.ts | 37 +++- 14 files changed, 392 insertions(+), 50 deletions(-) create mode 100644 packages/e2e/app/bars/[bar]/page.tsx create mode 100644 packages/e2e/app/layout.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bcd0be..029a9d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,13 +17,21 @@ ; ``` -- 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

= Extract< + export type RoutedQuery

= 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["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 & { + 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(): RoutedQuery; + export const useParams = () => RoutedQuery; } 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

= Extract< + export type RoutedQuery

= 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

= Extract< + export type RoutedQuery

= 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

= Extract< + export type RoutedQuery

= Extract< Route, { pathname: P } >["query"]; 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 { @@ -31,7 +32,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= 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["pathname"]; export type LinkProps = Omit & { - href: Route | StaticRoute | Omit; + href: Route | StaticRoute | Omit | RouteLiteral; locale?: false; } @@ -167,3 +168,76 @@ declare module "next/router" { export function useRouter

(): NextRouter

; } + +// 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["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 & { + 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 = () => RoutedQuery; +} 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 @@ +export default () =>

Bar
; 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 ( + + + {children} + + ); +} 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 @@ /// /// +/// // 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(usePathname()); + +expectType(useParams()); +expectType>(useParams<"/bars/[bar]">()); 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 ", 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

= Extract< + export type RoutedQuery

= 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["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 & { + 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(): RoutedQuery; + export const useParams = () => RoutedQuery; } ", ], @@ -261,7 +290,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= 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["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 & { + 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(): RoutedQuery; + export const useParams = () => RoutedQuery; } ", ], @@ -482,7 +540,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= 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["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 & { + 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(): RoutedQuery; + export const useParams = () => RoutedQuery; } ", ], @@ -702,7 +789,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= 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["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 & { + 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(): RoutedQuery; + export const useParams = () => RoutedQuery; } ", ], @@ -922,7 +1038,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= Extract< Route, { pathname: P } >["query"]; @@ -1122,7 +1238,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= Extract< Route, { pathname: P } >["query"]; @@ -1300,7 +1416,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= Extract< Route, { pathname: P } >["query"]; @@ -1476,7 +1592,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= Extract< Route, { pathname: P } >["query"]; @@ -1652,7 +1768,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= Extract< Route, { pathname: P } >["query"]; @@ -1828,7 +1944,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= Extract< Route, { pathname: P } >["query"]; @@ -2006,7 +2122,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= 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["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 & { + 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(): RoutedQuery; + export const useParams = () => RoutedQuery; } ", ], @@ -2226,7 +2371,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= Extract< Route, { pathname: P } >["query"]; @@ -2419,7 +2564,7 @@ declare module "nextjs-routes" { [key: string]: string | string[] | undefined; }; - export type RoutedQuery

= Extract< + export type RoutedQuery

= Extract< Route, { pathname: P } >["query"]; 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

= Extract< + export type RoutedQuery

= 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["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 & { + 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(): RoutedQuery; + export const useParams = () => RoutedQuery; } `; }