Skip to content

Typesafety improvements #12019

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 32 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7ce143e
typescript language service plugin setup
pcattori Sep 17, 2024
ff7631d
simplify rollup config with `output.exports: "auto"`
pcattori Sep 17, 2024
fbcc3ad
vite node context refactor
pcattori Sep 17, 2024
c5aa105
typegen watch
pcattori Sep 18, 2024
eed704c
params typegen
pcattori Sep 19, 2024
7d1a623
update playground for typegen
pcattori Sep 19, 2024
ab5e307
refactor
pcattori Sep 19, 2024
6440d23
typegen exports
pcattori Sep 19, 2024
6245f09
type tests
pcattori Sep 19, 2024
624093f
decision doc: type inference
pcattori Sep 21, 2024
76ef8a1
pr feedback
pcattori Sep 24, 2024
60adb8c
arg-centric typegen
pcattori Sep 25, 2024
7de6935
use types from typegen in compiler template
pcattori Sep 25, 2024
a447ee0
typegen command
pcattori Sep 25, 2024
55fd1bf
update playgrounds to fix typechecking
pcattori Sep 25, 2024
3bba333
update cli snapshots
pcattori Sep 25, 2024
72a20c3
Fix vite-node resolution within TS plugin
markdalgleish Sep 26, 2024
722db5c
Merge pull request #12039 from remix-run/markdalgleish/fix-ts-plugin-…
pcattori Sep 26, 2024
50ba6c5
rename type utils to avoid autoimporting them within route modules
pcattori Sep 26, 2024
bdfefbe
typegen file comments
pcattori Sep 26, 2024
12b2606
only typegen if route file exists
pcattori Sep 26, 2024
07f9b5e
Merge branch 'dev' into pedro/typesafety-phase-1
pcattori Sep 28, 2024
197c225
clientLoader.hydrate types
pcattori Sep 28, 2024
38a2037
typegen as `.d.ts` instead of `.ts`
pcattori Sep 28, 2024
23c16a6
typegen for root route
pcattori Sep 30, 2024
1dd6884
inline ctx for ts plugin
pcattori Sep 30, 2024
dce0795
no more hardcoded app dir
pcattori Sep 30, 2024
f042b8c
decision doc rejected solutions section
pcattori Sep 30, 2024
92d4a70
fix HydrateFallback detection
pcattori Sep 30, 2024
42a5853
rename `DefaultProps` to `ComponentProps`
pcattori Oct 1, 2024
6eaf2d6
pr feedback
pcattori Oct 1, 2024
7e87c5d
changeset
pcattori Oct 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions .changeset/typesafety.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
---
"@react-router/dev": minor
"react-router": minor
---

### Typesafety improvements

React Router now generates types for each of your route modules.
You can access those types by importing them from `./+types/<route filename without extension>`.
For example:

```ts
// app/routes/product.tsx
import type * as Route from "./+types/product";

export function loader({ params }: Route.LoaderArgs) {}

export default function Component({ loaderData }: Route.ComponentProps) {}
```

This initial implementation targets type inference for:

- `Params` : Path parameters from your routing config in `routes.ts` including file-based routing
- `LoaderData` : Loader data from `loader` and/or `clientLoader` within your route module
- `ActionData` : Action data from `action` and/or `clientAction` within your route module

These types are then used to create types for route export args and props:

- `LoaderArgs`
- `ClientLoaderArgs`
- `ActionArgs`
- `ClientActionArgs`
- `HydrateFallbackProps`
- `ComponentProps` (for the `default` export)
- `ErrorBoundaryProps`

In the future, we plan to add types for the rest of the route module exports: `meta`, `links`, `headers`, `shouldRevalidate`, etc.
We also plan to generate types for typesafe `Link`s:

```tsx
<Link to="/products/:id" params={{ id: 1 }} />
// ^^^^^^^^^^^^^ ^^^^^^^^^
// typesafe `to` and `params` based on the available routes in your app
```

#### Setup

React Router will generate types into a `.react-router/` directory at the root of your app.
This directory is fully managed by React Router and is derived based on your route config (`routes.ts`).

👉 ** Add `.react-router/` to `.gitignore` **

```txt
.react-router
```

You should also ensure that generated types for routes are always present before running typechecking,
especially for running typechecking in CI.

👉 ** Add `react-router typegen` to your `typecheck` command in `package.json` **

```json
{
"scripts": {
"typecheck": "react-router typegen && tsc"
}
}
```

To get TypeScript to use those generated types, you'll need to add them to `include` in `tsconfig.json`.
And to be able to import them as if they files next to your route modules, you'll also need to configure `rootDirs`.

👉 ** Configure `tsconfig.json` for generated types **

```json
{
"include": [".react-router/types/**/*"],
"compilerOptions": {
"rootDirs": [".", "./.react-router/types"]
}
}
```

#### `typegen` command

You can manually generate types with the new `typegen` command:

```sh
react-router typegen
```

However, manual type generation is tedious and types can get out of sync quickly if you ever forget to run `typegen`.
Instead, we recommend that you setup our new TypeScript plugin which will automatically generate fresh types whenever routes change.
That way, you'll always have up-to-date types.

#### TypeScript plugin

To get automatic type generation, you can use our new TypeScript plugin.

👉 ** Add the TypeScript plugin to `tsconfig.json` **

```json
{
"compilerOptions": {
"plugins": [{ "name": "@react-router/dev" }]
}
}
```

We plan to add some other goodies to our TypeScript plugin soon, including:

- Automatic `jsdoc` for route exports that include links to official docs
- Autocomplete for route exports
- Warnings for non-HMR compliant exports

##### VSCode

TypeScript looks for plugins registered in `tsconfig.json` in the local `node_modules/`,
but VSCode ships with its own copy of TypeScript that is installed outside of your project.
For TypeScript plugins to work, you'll need to tell VSCode to use the local workspace version of TypeScript.

👉 ** Ensure that VSCode is using the workspace version of TypeScript **

This should already be set up for you by a `.vscode/settings.json`:

```json
{
"typescript.tsdk": "node_modules/typescript/lib"
}
```

Alternatively, you can open up any TypeScript file and use <kbd>CMD</kbd>+<kbd>SHIFT</kbd>+<kbd>P</kbd> to find `Select TypeScript Version` and then select `Use Workspace Version`. You may need to quit VSCode and reopen it for this setting to take effect.

##### Troubleshooting

In VSCode, open up any TypeScript file in your project and then use <kbd>CMD</kbd>+<kbd>SHIFT</kbd>+<kbd>P</kbd> to select `Open TS Server log`.
There should be a log for `[react-router] setup` that indicates that the plugin was resolved correctly.
Then look for any errors in the log.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Date: 2022-07-11

Status: accepted
Status: Superseded by [#0012](./0012-type-inference.md)

## Context

Expand Down
Loading
Loading