Skip to content

feat: generate root params types#91019

Open
bgub wants to merge 1 commit intovercel:canaryfrom
bgub:feat/root-params-types-new
Open

feat: generate root params types#91019
bgub wants to merge 1 commit intovercel:canaryfrom
bgub:feat/root-params-types-new

Conversation

@bgub
Copy link
Contributor

@bgub bgub commented Mar 7, 2026

Summary

Generate type definitions for next/root-params from App Router root layouts.

This adds a root-params.d.ts file under .next/types during build, next dev, and next typegen, so imports from next/root-params get accurate autocomplete and type checking.

What Changed

  • Collect root param metadata from layout routes in the route types manifest
  • Generate .next/types/root-params.d.ts for next/root-params
  • Emit root param types in next build/dev/typegen
  • Infer undefined only when a param is not present in every root layout
  • Model mixed root param shapes correctly as unions
    • For example, string | string[] | undefined when the same param name appears with different shapes across roots
  • Remove stale root-params.d.ts when the feature is disabled or there are no root params

Why

next/root-params already works at runtime, but its types were not tailored to the current app.

This change closes that gap by generating declarations from the app's actual root layouts. Required params stay required for single-root apps, while multi-root apps correctly expose params that may be missing or have mixed segment shapes.

Testing

  • Added focused unit tests for root param type generation
  • Added a typecheck e2e test for generated root-params.d.ts

@nextjs-bot
Copy link
Collaborator

Allow CI Workflow Run

  • approve CI run for commit: 661b039

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

@bgub bgub marked this pull request as ready for review March 7, 2026 06:37
@mondyzzz-glitch
Copy link

感谢反馈!我们看到了你的feature请求。我们会尽快处理。

@nextjs-bot
Copy link
Collaborator

Failing test suites

Commit: 661b039 | About building and testing Next.js

pnpm test-dev test/e2e/app-dir/app-root-params-getters/typecheck.test.ts (job)

  • app-root-param-getters - typecheck (multiple-roots) > should generate root-params.d.ts with non-universal param (DD)
  • app-root-param-getters - typecheck (simple) > should generate root-params.d.ts with correct types (DD)
  • app-root-param-getters - typecheck (simple) > should be included via tsconfig glob pattern (DD)
Expand output

● app-root-param-getters - typecheck (simple) › should generate root-params.d.ts with correct types

ENOENT: no such file or directory, open '/tmp/next-install-6d4c6c176ca5c72af61093486a8f5ce4b12f58e74a56edc6098f5f75754ce271/.next/types/root-params.d.ts'

  16 |     )
  17 |
> 18 |     const content = fs.readFileSync(rootParamsTypesPath, 'utf8')
     |                        ^
  19 |
  20 |     // lang and locale should be universal (single root layout branch for [lang]/[locale])
  21 |     // but there are also catch-all and optional-catch-all branches, so they're not in ALL root layouts

  at Object.readFileSync (e2e/app-dir/app-root-params-getters/typecheck.test.ts:18:24)

● app-root-param-getters - typecheck (simple) › should be included via tsconfig glob pattern

expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  45 |       'root-params.d.ts'
  46 |     )
> 47 |     expect(fs.existsSync(rootParamsTypesPath)).toBe(true)
     |                                                ^
  48 |   })
  49 | })
  50 |

  at Object.toBe (e2e/app-dir/app-root-params-getters/typecheck.test.ts:47:48)

● app-root-param-getters - typecheck (multiple-roots) › should generate root-params.d.ts with non-universal param

ENOENT: no such file or directory, open '/tmp/next-install-b9e2e05cf9ba5f9432a9e7a29249b351e3298daaaa40e1e1a1d993c042b2c7bd/.next/types/root-params.d.ts'

  62 |     )
  63 |
> 64 |     const content = fs.readFileSync(rootParamsTypesPath, 'utf8')
     |                        ^
  65 |
  66 |     // id is only in dashboard root layout, not in landing root layout
  67 |     // so it should be non-universal → Promise<string | undefined>

  at Object.readFileSync (e2e/app-dir/app-root-params-getters/typecheck.test.ts:64:24)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants