Next.js 10,514 reads your app directory and writes a .d.ts describing every route it found. Run next typegen in a project with app/products/page.tsx, app/products/[sku]/page.tsx and app/api/health/route.ts, and .next/types/routes.d.ts holds this:
type AppRoutes = "/" | "/products" | "/products/[sku]"
type AppRouteHandlerRoutes = "/api/health"
interface ParamMap {
"/products": {}
"/products/[sku]": { "sku": string; }
}
declare global {
interface PageProps<AppRoute extends AppRoutes> {
params: Promise<ParamMap[AppRoute]>
searchParams: Promise<Record<string, string | string[] | undefined>>
}
}PageProps, LayoutProps and RouteContext — the last for route handlers — are global: no import, and each takes the route's own path as its type argument. params is a Promise, so the async params of Cookies and Params are baked in and forgetting to await is a type error too. A page types itself from where it sits, function ProductPage({ params }: PageProps<'/products/[sku]'>), so destructuring slug from a copied blog example fails the build. Mistyping the route argument is caught too, and drags params down to unknown in a second, consequential error:
app/products/[sku]/page.tsx(2,11): error TS2339: Property 'slug' does not exist on
type '{ sku: string; }'.
app/products/[sku]/page.tsx(1,65): error TS2344: Type '"/product/[sku]"' does not
satisfy the constraint 'AppRoutes'.Typed links
Route types cover href too, but that half is opt-in because it changes the type of every <Link> in the project. Set typedRoutes: true in next.config.ts and typegen also writes .next/types/link.d.ts, a template-literal type built from your route table; it validates string and template literals, and useRouter's push, replace and prefetch. Three links — ` href={/products/${sku}} on line 9, href={/product/${skus[0]}} on line 11, href={path} with path: string` on line 12 — check thus:
app/products/page.tsx(11,13): error TS2322: Type '`/product/${string}`' is not
assignable to type 'UrlObject | RouteImpl<`/product/${string}`>'.
app/products/page.tsx(12,13): error TS2322: Type 'string' is not assignable to type
'UrlObject | RouteImpl<string>'.Line 9 passes even though sku is a plain string: the type accepts anything where a dynamic segment goes. Line 11 fails because /product/ is not a prefix that exists. Line 12 carries no information at all, so it needs import type { Route } from 'next' and href={path as Route}. A component wrapping Link takes href as Route<T> | URL with T extends string.