Skip to content

Commit 3f122a4

Browse files
authored
Docs/typed routes snippets (#83132)
A few more improvements to typed routes and friends - showing usage of router methods from `next/navigation` - using Route in other data structures
1 parent 168ed36 commit 3f122a4

File tree

1 file changed

+70
-10
lines changed

1 file changed

+70
-10
lines changed

docs/01-app/03-api-reference/05-config/02-typescript.mdx

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -150,20 +150,44 @@ Next.js will generate a link definition in `.next/types` that contains informati
150150
```
151151
{/* prettier-ignore-end */}
152152

153-
Currently, experimental support includes any string literal, including dynamic segments. For non-literal strings, you currently need to manually cast the `href` with `as Route`:
153+
Currently, support includes any string literal, including dynamic segments. For non-literal strings, you need to manually cast with `as Route`. The example below shows both `next/link` and `next/navigation` usage:
154154

155-
```tsx
156-
import type { Route } from 'next';
155+
```tsx filename="app/example-client.tsx"
156+
'use client'
157+
158+
import type { Route } from 'next'
157159
import Link from 'next/link'
160+
import { useRouter } from 'next/navigation'
158161

159-
// No TypeScript errors if href is a valid route
160-
<Link href="/about" />
161-
<Link href="/blog/nextjs" />
162-
<Link href={`/blog/${slug}`} />
163-
<Link href={('/blog' + slug) as Route} />
162+
export default function Example() {
163+
const router = useRouter()
164+
const slug = 'nextjs'
164165

165-
// TypeScript errors if href is not a valid route
166-
<Link href="/aboot" />
166+
return (
167+
<>
168+
{/* Link: literal and dynamic */}
169+
<Link href="/about" />
170+
<Link href={`/blog/${slug}`} />
171+
<Link href={('/blog' + slug) as Route} />
172+
{/* TypeScript error if href is not a valid route */}
173+
<Link href="/aboot" />
174+
175+
{/* Router: literal and dynamic strings are validated */}
176+
<button onClick={() => router.push('/about')}>Push About</button>
177+
<button onClick={() => router.replace(`/blog/${slug}`)}>
178+
Replace Blog
179+
</button>
180+
<button onClick={() => router.prefetch('/contact')}>
181+
Prefetch Contact
182+
</button>
183+
184+
{/* For non-literal strings, cast to Route */}
185+
<button onClick={() => router.push(('/blog' + slug) as Route)}>
186+
Push Non-literal Blog
187+
</button>
188+
</>
189+
)
190+
}
167191
```
168192

169193
The same applies for redirecting routes defined by middleware:
@@ -203,6 +227,42 @@ function Card<T extends string>({ href }: { href: Route<T> | URL }) {
203227
}
204228
```
205229

230+
You can also type a simple data structure and iterate to render links:
231+
232+
```ts filename="components/nav-items.ts"
233+
import type { Route } from 'next'
234+
235+
type NavItem<T extends string = string> = {
236+
href: T
237+
label: string
238+
}
239+
240+
export const navItems: NavItem<Route>[] = [
241+
{ href: '/', label: 'Home' },
242+
{ href: '/about', label: 'About' },
243+
{ href: '/blog', label: 'Blog' },
244+
]
245+
```
246+
247+
Then, map over the items to render `Link`s:
248+
249+
```tsx filename="components/nav.tsx"
250+
import Link from 'next/link'
251+
import { navItems } from './nav-items'
252+
253+
export function Nav() {
254+
return (
255+
<nav>
256+
{navItems.map((item) => (
257+
<Link key={item.href} href={item.href}>
258+
{item.label}
259+
</Link>
260+
))}
261+
</nav>
262+
)
263+
}
264+
```
265+
206266
> **How does it work?**
207267
>
208268
> When running `next dev` or `next build`, Next.js generates a hidden `.d.ts` file inside `.next` that contains information about all existing routes in your application (all valid routes as the `href` type of `Link`). This `.d.ts` file is included in `tsconfig.json` and the TypeScript compiler will check that `.d.ts` and provide feedback in your editor about invalid links.

0 commit comments

Comments
 (0)