-
-
Notifications
You must be signed in to change notification settings - Fork 10.7k
Description
Reproduction
https://stackblitz.com/edit/github-fguzcsck?file=app%2Froutes%2Fhome.tsx
Note that you may need to click in the editor and add then remove a space to trigger a type-checking pass.
System Info
System:
OS: Linux 5.0 undefined
CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
Memory: 0 Bytes / 0 Bytes
Shell: 1.0 - /bin/jsh
Binaries:
Node: 20.19.1 - /usr/local/bin/node
Yarn: 1.22.19 - /usr/local/bin/yarn
npm: 10.8.2 - /usr/local/bin/npm
pnpm: 8.15.6 - /usr/local/bin/pnpm
npmPackages:
@react-router/dev: ^7.5.3 => 7.6.3
@react-router/node: ^7.5.3 => 7.6.3
@react-router/serve: ^7.5.3 => 7.6.3
react-router: ^7.5.3 => 7.6.3
vite: ^6.3.3 => 6.3.5
Used Package Manager
npm
Expected Behavior
As shown as the reproduction, the current runtime behavior of generatePath
is as follows:
generatePath("/users/:id?", { id: "123" })
returns/users/123
.generatePath("/users/:id?", { id: null })
returns/users
.generatePath("/users/:id?", { id: undefined })
returns/users
.generatePath("/users/:id?", {})
returns/users
.
Because generatePath
uses == null
and != null
checks in its implementation, it accepts either null
or undefined
for optional parameters.
react-router/packages/react-router/lib/router/utils.ts
Lines 1091 to 1092 in 0dea762
const stringify = (p: any) => | |
p == null ? "" : typeof p === "string" ? p : String(p); |
invariant(optional === "?" || param != null, `Missing ":${key}" param`); |
I would expect that its type signature would similarly accommodate all these options.
Actual Behavior
The params
argument in generatePath
currently has the type params: { [key in PathParam<Path>]: string | null; }
, meaning it requires missing parameters to be specified as null
, and doesn't allow them to be specified as undefined
or omitted entirely.
react-router/packages/react-router/lib/router/utils.ts
Lines 1072 to 1074 in 0dea762
params: { | |
[key in PathParam<Path>]: string | null; | |
} = {} as any |
This is problematic because it rules out some of the usages that yield valid runtime behavior.
The expression generatePath("/users/:id?", { id: undefined })
currently gives the following type error:

The expression generatePath("/users/:id?", {})
currently gives the following type error:

To match the runtime behavior of generatePath
, we should instead be using the type params: { [key in PathParam<Path>]?: string | null | undefined; }
. The ?
would allow a parameter to be omitted, and the | undefined
would allow it to be undefined
.
Note that once this change is made, the default value for params
could also be simplified from = {} as any
to just = {}
, since {}
would now be a valid value for the specified type.