Skip to content

Commit e2f7cb2

Browse files
icyJosephvercel[bot]molebox
authored
docs: Type narrowing using LayoutProps, PageProps (#83692)
Make a couple of clarifications: - type resolved by the helpers - ways to narrow down to a narrower union --------- Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> Co-authored-by: Rich Haines <[email protected]>
1 parent 944bc94 commit e2f7cb2

File tree

1 file changed

+20
-0
lines changed

1 file changed

+20
-0
lines changed

docs/01-app/03-api-reference/03-file-conventions/dynamic-routes.mdx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,33 @@ The difference between **catch-all** and **optional catch-all** segments is that
113113

114114
When using TypeScript, you can add types for `params` depending on your configured route segment — use [`PageProps<'/route'>`](/docs/app/api-reference/file-conventions/page#page-props-helper), [`LayoutProps<'/route'>`](/docs/app/api-reference/file-conventions/layout#layout-props-helper), or [`RouteContext<'/route'>`](/docs/app/api-reference/file-conventions/route#route-context-helper) to type `params` in `page`, `layout`, and `route` respectively.
115115

116+
Route `params` values are typed as `string`, `string[]`, or `undefined` (for optional catch-all segments), because their values aren't known until runtime. Users can enter any URL into the address bar, and these broad types help ensure that your application code handles all these possible cases.
117+
116118
| Route | `params` Type Definition |
117119
| ----------------------------------- | ---------------------------------------- |
118120
| `app/blog/[slug]/page.js` | `{ slug: string }` |
119121
| `app/shop/[...slug]/page.js` | `{ slug: string[] }` |
120122
| `app/shop/[[...slug]]/page.js` | `{ slug?: string[] }` |
121123
| `app/[categoryId]/[itemId]/page.js` | `{ categoryId: string, itemId: string }` |
122124

125+
If you're working on a route where `params` can only have a fixed number of valid values, such as a `[locale]` param with a known set of language codes, you can use runtime validation to handle any invalid params a user may enter, and let the rest of your application work with the narrower type from your known set.
126+
127+
```tsx filename="/app/[locale]/page.tsx"
128+
import { notFound } from 'next/navigation'
129+
import type { Locale } from '@i18n/types'
130+
import { isValidLocale } from '@i18n/utils'
131+
132+
function assertValidLocale(value: string): asserts value is Locale {
133+
if (!isValidLocale(value)) notFound()
134+
}
135+
136+
export default async function Page(props: PageProps<'/[locale]'>) {
137+
const { locale } = await props.params // locale is typed as string
138+
assertValidLocale(locale)
139+
// locale is now typed as Locale
140+
}
141+
```
142+
123143
## Behavior
124144

125145
- Since the `params` prop is a promise. You must use `async`/`await` or React's use function to access the values.

0 commit comments

Comments
 (0)