Skip to content

Latest commit

 

History

History
108 lines (95 loc) · 3.51 KB

typescript.md

File metadata and controls

108 lines (95 loc) · 3.51 KB

Typed Routes

This plugin generates a d.ts file with all the typing overrides when the dev or build server is ran. Make sure to include it in your tsconfig.json's (or jsconfig.json's) include or files property:

{
  // ...
  "include": [
    /* ... */
    "./typed-router.d.ts",
  ]
  // ...
}

The generated Route Map is picked up by unplugin-vue-router/client types and configures the vue-router types to be aware of the routes in your application. Making everything type safe!

::: tip You can commit the newly added .d.ts files to your repository to make your life easier. :::

// ---cut-start---
import 'unplugin-vue-router/client'
import './typed-router.d'
// ---cut-end---
// @moduleResolution: bundler
import { useRouter, useRoute } from 'vue-router'
const router = useRouter()
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'.

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:

export {} // needed in .d.ts files
import type {
  RouteRecordInfo,
  ParamValue,
  // these are other param helper types
  ParamValueOneOrMore,
  ParamValueZeroOrMore,
  ParamValueZeroOrOne,
  RouteMeta,
} from 'vue-router'
declare module 'vue-router/auto-routes' {
  export interface RouteNamedMap {
    // the key is the name and should match the first generic of RouteRecordInfo
    'custom-dynamic-name': RouteRecordInfo<
      'custom-dynamic-name',
      '/added-during-runtime/[...path]',
      // these are the raw param types (accept numbers, strings, booleans, etc)
      { path: ParamValue<true> },
      // these are the normalized params as found in useRoute().params
      { path: ParamValue<false> },
      // these are the `meta` fields
      RouteMeta,
      // this is a union of all children route names
      // if the route does not have nested routes, pass `never` or omit this generic entirely
      'custom-dynamic-child-name'
    >
    'custom-dynamic-child-name': RouteRecordInfo<
      'custom-dynamic-child-name',
      '/added-during-runtime/[...path]/child',
      { path: ParamValue<true> },
      { path: ParamValue<false> },
      RouteMeta,
      never
    >
  }
}

You can now pass a type param to the generic route location types to narrow down the type of the route:

// ---cut-start---
import 'unplugin-vue-router/client'
import './typed-router.d'
import { useRoute, type RouteLocationNormalizedLoaded } from 'vue-router'
// ---cut-end---
// @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.
// 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.
const userRouteWithIdCasted = useRoute() as RouteLocationNormalizedLoaded<'/users/[id]'>
userRouteWithIdCasted.params.id
// Better way, but no autocompletion.
const userRouteWithIdTypeParam = useRoute<'/users/[id]'>()
userRouteWithIdTypeParam.params.id
// 👇 This one is the easiest to write because it autocompletes.
const userRouteWithIdParam = useRoute('/users/[id]')
userRouteWithIdParam.name
//                   ^?