Skip to content

Commit 66613c0

Browse files
authored
Fix contxt types for Route.LoaderArgs, add upgrade docs (#12145)
1 parent 211f46d commit 66613c0

File tree

2 files changed

+40
-6
lines changed

2 files changed

+40
-6
lines changed

docs/upgrading/remix.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,34 @@ If you have an `entry.server.tsx` and/or an `entry.client.tsx` file in your appl
9696
| `entry.server.tsx` | `<RemixServer>` | ➡️ | `<ServerRouter>` |
9797
| `entry.client.stx` | `<RemixBrowser>` | ➡️ | `<HydratedRouter>` |
9898

99+
### Step 7 - Update types for `AppLoadContext`
100+
101+
<docs-info>This is only applicable if you were using a custom server in Remix v2. If you were using `remix-serve` you can skip this step.</docs-info>
102+
103+
If you were using `getLoadContext` in your Remix app, then you'll notice that the `LoaderFunctionArgs`/`ActionFunctionArgs` types now type the `context` parameter incorrectly (optional and typed as `any`). These types accept a generic for the `context` type but even that still leaves the property as optional because it does not exist in React Router SPA apps.
104+
105+
The proper long term fix is to move to the new [`Route.LoaderArgs`][server-loaders]/[`Route.ActionArgs`][server-actions] types from the new typegen in React Router v7.
106+
107+
However, the short-term solution to ease the upgrade is to use TypeScript's [module augmentation][ts-module-augmentation] feature to override the built in `LoaderFunctionArgs`/`ActionFunctionArgs` interfaces.
108+
109+
You can do this with the following code in your `vite.config.ts`:
110+
111+
```ts filename="vite.config.ts"
112+
// Your AppLoadContext used in v2
113+
interface AppLoadContext {
114+
whatever: string;
115+
}
116+
117+
// Tell v7 the type of the context and that it is non-optional
118+
declare module "react-router" {
119+
interface LoaderFunctionArgs {
120+
context: AppLoadContext;
121+
}
122+
}
123+
```
124+
125+
This should allow you to upgrade and ship your application on React Router v7, and then you can incrementally migrate routes to the new typegen approach.
126+
99127
## Known Prerelease Issues
100128

101129
### Typesafety
@@ -127,3 +155,6 @@ let data = useLoaderData<typeof loader>();
127155
[routing]: ../start/routing
128156
[fs-routing]: ../misc/file-route-conventions
129157
[v7-changelog-types]: https://github.com/remix-run/react-router/blob/release-next/CHANGELOG.md#typesafety-improvements
158+
[server-loaders]: ../start/data-loading#server-data-loading
159+
[server-actions]: ../start/actions#server-actions
160+
[ts-module-augmentation]: https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation

packages/react-router/lib/types.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,13 @@ type _CreateActionData<ServerActionData, ClientActionData> = Awaited<
8888
undefined
8989
>
9090

91-
type DataFunctionArgs<Params> = {
91+
type ClientDataFunctionArgs<Params> = {
9292
request: Request;
9393
params: Params;
94-
context?: AppLoadContext;
94+
};
95+
96+
type ServerDataFunctionArgs<Params> = ClientDataFunctionArgs<Params> & {
97+
context: AppLoadContext;
9598
};
9699

97100
// prettier-ignore
@@ -122,21 +125,21 @@ type Serialize<T> =
122125

123126
undefined
124127

125-
export type CreateServerLoaderArgs<Params> = DataFunctionArgs<Params>;
128+
export type CreateServerLoaderArgs<Params> = ServerDataFunctionArgs<Params>;
126129

127130
export type CreateClientLoaderArgs<
128131
Params,
129132
T extends RouteModule
130-
> = DataFunctionArgs<Params> & {
133+
> = ClientDataFunctionArgs<Params> & {
131134
serverLoader: () => Promise<ServerDataFrom<T["loader"]>>;
132135
};
133136

134-
export type CreateServerActionArgs<Params> = DataFunctionArgs<Params>;
137+
export type CreateServerActionArgs<Params> = ServerDataFunctionArgs<Params>;
135138

136139
export type CreateClientActionArgs<
137140
Params,
138141
T extends RouteModule
139-
> = DataFunctionArgs<Params> & {
142+
> = ClientDataFunctionArgs<Params> & {
140143
serverAction: () => Promise<ServerDataFrom<T["action"]>>;
141144
};
142145

0 commit comments

Comments
 (0)