Skip to content

Commit

Permalink
Fix contxt types for Route.LoaderArgs, add upgrade docs (#12145)
Browse files Browse the repository at this point in the history
  • Loading branch information
brophdawg11 authored Oct 17, 2024
1 parent 211f46d commit 66613c0
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 6 deletions.
31 changes: 31 additions & 0 deletions docs/upgrading/remix.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,34 @@ If you have an `entry.server.tsx` and/or an `entry.client.tsx` file in your appl
| `entry.server.tsx` | `<RemixServer>` | ➡️ | `<ServerRouter>` |
| `entry.client.stx` | `<RemixBrowser>` | ➡️ | `<HydratedRouter>` |

### Step 7 - Update types for `AppLoadContext`

<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>

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.

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.

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.

You can do this with the following code in your `vite.config.ts`:

```ts filename="vite.config.ts"
// Your AppLoadContext used in v2
interface AppLoadContext {
whatever: string;
}

// Tell v7 the type of the context and that it is non-optional
declare module "react-router" {
interface LoaderFunctionArgs {
context: AppLoadContext;
}
}
```

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.

## Known Prerelease Issues

### Typesafety
Expand Down Expand Up @@ -127,3 +155,6 @@ let data = useLoaderData<typeof loader>();
[routing]: ../start/routing
[fs-routing]: ../misc/file-route-conventions
[v7-changelog-types]: https://github.com/remix-run/react-router/blob/release-next/CHANGELOG.md#typesafety-improvements
[server-loaders]: ../start/data-loading#server-data-loading
[server-actions]: ../start/actions#server-actions
[ts-module-augmentation]: https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
15 changes: 9 additions & 6 deletions packages/react-router/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,13 @@ type _CreateActionData<ServerActionData, ClientActionData> = Awaited<
undefined
>

type DataFunctionArgs<Params> = {
type ClientDataFunctionArgs<Params> = {
request: Request;
params: Params;
context?: AppLoadContext;
};

type ServerDataFunctionArgs<Params> = ClientDataFunctionArgs<Params> & {
context: AppLoadContext;
};

// prettier-ignore
Expand Down Expand Up @@ -122,21 +125,21 @@ type Serialize<T> =

undefined

export type CreateServerLoaderArgs<Params> = DataFunctionArgs<Params>;
export type CreateServerLoaderArgs<Params> = ServerDataFunctionArgs<Params>;

export type CreateClientLoaderArgs<
Params,
T extends RouteModule
> = DataFunctionArgs<Params> & {
> = ClientDataFunctionArgs<Params> & {
serverLoader: () => Promise<ServerDataFrom<T["loader"]>>;
};

export type CreateServerActionArgs<Params> = DataFunctionArgs<Params>;
export type CreateServerActionArgs<Params> = ServerDataFunctionArgs<Params>;

export type CreateClientActionArgs<
Params,
T extends RouteModule
> = DataFunctionArgs<Params> & {
> = ClientDataFunctionArgs<Params> & {
serverAction: () => Promise<ServerDataFrom<T["action"]>>;
};

Expand Down

0 comments on commit 66613c0

Please sign in to comment.