Skip to content

feat: better types for params #13543

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 6, 2025
Merged

feat: better types for params #13543

merged 9 commits into from
May 6, 2025

Conversation

pcattori
Copy link
Contributor

@pcattori pcattori commented May 6, 2025

The types registered by the new generated +routes-pre.ts file are used internally to compute more precise params types for each route. Specifically, each route's params are a union of all possible params from any pages (visitable URLs) that include that route.

For example:

// routes.ts
import { type RouteConfig, route } from "@react-router/dev/routes";
          
export default [
  route("parent/:p", "routes/parent.tsx", [
    route("route/:r", "routes/route.tsx", [
      route("child1/:c1a/:c1b", "routes/child1.tsx"),
      route("child2/:c2a/:c2b", "routes/child2.tsx")
    ]),
  ]),
] satisfies RouteConfig;

Previously, we calculated the types for routes/route to be { p: string, r: string }, but this is incorrect as it ignores possible params from child routes.

Let's consider the possible params types for routes/route:

Path Page includes routes/route? Params type
parent/1 { p: string }
parent/1/route/2 { p: string, r: string }
parent/1/route/2/child1/3/4 { p: string, r: string, c1a: string, c1b: string }
parent/1/route/2/child2/5/6 { p: string, r: string, c2a: string, c2b: string }

So the correct params type is a union of all the params types for pages that includes routes/route:

type Params =
  | { p: string, r: string }
  | { p: string, r: string, c1a: string, c1b: string }
  | { p: string, r: string, c2a: string, c2b: string }

We could stop here, but this will lead to poor DX as autocompletion for params. will only suggest fields that exist in all members of the union. To fix this, we normalize the members of the union and add ?: undefined entries for any fields not present in the current member but present in other members:

type NormalizedParams =
  | { p: string, r: string, c1a?: undefined, c1b?: undefined, c2a?: undefined, c2b?: undefined }
  | { p: string, r: string, c1a: string, c1b: string, c2a?: undefined, c2b?: undefined }
  | { p: string, r: string, c1a?: undefined, c1b?: undefined, c2a: string, c2b: string }

This new type is equivalent to the unnormalized Params type, but allows for better DX from autocompletions.


This PR also reorganizes the generated files for types as:

  • +future.ts : Automatic registration of future flag types
  • +pages.ts : Types relevant to each visitable URL including params. Powers href types.
  • +routes-pre.ts : Types derived from routes config, prior to seeing any route modules
  • +routes-post.ts : Coming soon! Not part of this PR, but this will allow us to register module-aware types for routes!
  • +server-build.d.ts : Types for virtual:react-router/server-build (previously +virtual.d.ts)

TODO

  • unstage todo.md + playground changes
  • Remove outdated typegen modules
  • Fix existing typegen tests
  • test for parent, route, child1, child2
  • Tests for Normalize
  • Changeset
  • clean out old +register and +virtual from existing projects?
  • fix params type for layouts

Copy link

changeset-bot bot commented May 6, 2025

🦋 Changeset detected

Latest commit: d152143

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 11 packages
Name Type
@react-router/dev Patch
react-router Patch
@react-router/fs-routes Patch
@react-router/remix-routes-option-adapter Patch
@react-router/architect Patch
@react-router/cloudflare Patch
react-router-dom Patch
@react-router/express Patch
@react-router/node Patch
@react-router/serve Patch
create-react-router Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pcattori pcattori force-pushed the pedro/better-types-for-params branch from 656a9a3 to ae73463 Compare May 6, 2025 15:19
@pcattori pcattori linked an issue May 6, 2025 that may be closed by this pull request
@pcattori pcattori marked this pull request as ready for review May 6, 2025 18:59
@pcattori pcattori merged commit 0423079 into dev May 6, 2025
8 checks passed
@pcattori pcattori deleted the pedro/better-types-for-params branch May 6, 2025 19:26
@MichaelDeBoey MichaelDeBoey changed the title Better types for params feat: better types for params May 7, 2025
Copy link
Contributor

🤖 Hello there,

We just published version 7.6.1 which includes this pull request. If you'd like to take it for a test run please try it out and let us know what you think!

Thanks!

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.

[Bug]: Params type incomplete [Bug]: (v7) Layout routes params are generated as an empty object missing actual params
2 participants