Skip to content

docs: enhance typed-router.d.ts docs and add section for using sfc-typed-router #687

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
101 changes: 85 additions & 16 deletions docs/guide/typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,43 @@ router.push('')

## Extra types

You can always take a look at the generated `typed-router.d.ts` file to inspect what are the generated types. `unplugin-vue-router` creates a `RouteNamedMap` interface and exports it from `'vue-router/auto-routes'`.
### `typed-router.d.ts` contents
You can always take a look at the generated `typed-router.d.ts` file to inspect what are the generated types. `unplugin-vue-router` creates and exports interfaces and helper types from `'vue-router/auto-routes'`:
- `RouteNamedMap` interface
- `_RouteFileInfoMap` interface
- `_RouteNamesForFilePath` helper type

#### `RouteNamedMap`
This interface maps route names to “route records”, containing the types for each route. A route record includes a route’s name, path, typed params and a list of its child route names.

#### `_RouteFileInfoMap`
This interface is used by the [`sfc-typed-router` Volar plugin](#using-the-sfc-typed-router-volar-plugin), if enabled. It maps page component file paths to all route names and views that could be displayed within these components.

#### `_RouteNamesForFilePath`
This is a helper type, used by the [`sfc-typed-router` Volar plugin](#using-the-sfc-typed-router-volar-plugin) to enhance typings for `useRoute()` and `$route`, if enabled. It returns the route names corresponding to a page component’s file path, or falls back to `keyof RouteNamedMap` in non-page components.

### Manually typing dynamically added routes
```ts
import type { RouteNamedMap } from 'vue-router/auto-routes'
```

This interface contains all the routes in your application along with their metadata. Augment it to add types for **dynamic routes** that are added during runtime:
The `RouteNamedMap` interface contains all the routes in your application along with their metadata. You can augment it to add types for **dynamic routes** that are added during runtime.

Note that, if you are using the [`sfc-typed-router` Volar plugin](#using-the-sfc-typed-router-volar-plugin), you should also augment the `_RouteFileInfoMap` interface for every dynamically added route corresponding to a page component.

```ts
export {} // needed in .d.ts files
import type {
RouteRecordInfo,
ParamValue,
// these are other param helper types
ParamValueOneOrMore,
ParamValueZeroOrMore,
ParamValueZeroOrOne,
} from 'vue-router'

declare module 'vue-router/auto-routes' {
import type {
RouteRecordInfo,
ParamValue,
// these are other param helper types
ParamValueOneOrMore,
ParamValueZeroOrMore,
ParamValueZeroOrOne,
} from 'vue-router'

export interface RouteNamedMap {
// the key is the name and should match the first generic of RouteRecordInfo
'custom-dynamic-name': RouteRecordInfo<
Expand All @@ -73,10 +91,25 @@ declare module 'vue-router/auto-routes' {
never
>
}

export interface _RouteFileInfoMap {
// the key is the file path and should match the page component's file path
'/added-during-runtime/[...path].vue': {
// these are the route names that can be displayed within this component
routes: 'custom-dynamic-name' | 'custom-dynamic-child-name'
// these are the views that can be used in this file
views: 'default'
}

'/added-during-runtime/[...path]/child.vue': {
routes: 'custom-dynamic-child-name'
views: never
}
}
}
```

You can now pass a _type param_ to the generic route location types to narrow down the type of the route:
You can now pass a _type param_ to the generic route location types to narrow down the type of the route. This automatically includes any child routes typings as well:

```ts twoslash
// ---cut-start---
Expand All @@ -87,19 +120,55 @@ import { useRoute, type RouteLocationNormalizedLoaded } from 'vue-router'
// @errors: 2322 2339
// @moduleResolution: bundler
// These are all valid ways to get a typed route and return the
// provided route's and any of its child routes' typings.
// provided routes and any of its child routes typings.
// Note that `/users/[id]/edit` is a child route
// of `/users/[id]` in this example.

// Not recommended, since this leaves out any child routes' typings.
// Not recommended, since this leaves out any child routes typings.
const userRouteWithIdCasted =
useRoute() as RouteLocationNormalizedLoaded<'/users/[id]'>
userRouteWithIdCasted.params.id
// Better way, but no autocompletion.

// Better way. Includes child routes’ typings, but no autocompletion.
const userRouteWithIdTypeParam = useRoute<'/users/[id]'>()
userRouteWithIdTypeParam.params.id
// 👇 This one is the easiest to write because it autocompletes.

// 👇 This one is the easiest to write because it both
// autocompletes and includes child routes’ typings.
const userRouteWithIdParam = useRoute('/users/[id]')
userRouteWithIdParam.name
// ^?
userRouteWithIdParam.params.id
```

### Using the `sfc-typed-router` Volar plugin
This Volar plugin automatically types `useRoute()` and `$route` correctly in page components, so you don’t have to write code like `useRoute('/users/[id]')`, allowing you to write less code.

To start using the plugin, add the following to the `tsconfig.json` file that includes your Vue files:
```json
{
// ...
"vueCompilerOptions": {
"plugins": [
"unplugin-vue-router/volar/sfc-typed-router"
]
}
}
```

As long as this plugin isn’t enabled in Nuxt by default with `experimental.typedPages: true` or through any other experimental feature flag, you should manually add the plugin via `nuxt.config.ts`:
```ts
export default defineNuxtConfig({
// ...
typescript: {
tsConfig: {
vueCompilerOptions: {
plugins: [
'unplugin-vue-router/volar/sfc-typed-router',
],
},
},
},
})
```

When using the `sfc-typed-router` Volar plugin, `useRoute()` and `$route` are typed automatically for page components under the hood, so you don’t have to do it manually.
4 changes: 3 additions & 1 deletion docs/nuxt/getting-started.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Nuxt

Currently, this plugin is included as an experimental setting in Nuxt. You can enable it by adding the following to your `nuxt.config.js`:
Currently, this plugin is included as an experimental setting in Nuxt. You can enable it by adding the following to your `nuxt.config.ts`:

```ts{2-4}
export default defineNuxtConfig({
Expand All @@ -9,3 +9,5 @@ export default defineNuxtConfig({
},
})
```

The `sfc-typed-router` Volar plugin, that automatically types `useRoute()` and `$route` in page components, cannot be enabled using a feature flag in Nuxt at this time. Read how to enable it here: [Using the `sfc-typed-router` Volar plugin](/guide/typescript#using-the-sfc-typed-router-volar-plugin).
Loading