With vue-routes-to-types libruary. Just 4 steps:
npm i vue-routes-to-types
- Marked your routes
const routes = [/*...*/] as const satisfies NamedRouteRecordRaw[]
- Call to magic
type RoutesMap = GenerateRoutesMap<typeof routes>
- Attach it to vue-router TypesConfig RouteNamedMap
More detailed sample located below on this page.
Of course since v4.4.0+ Vue Router can work with typed routes. Link to official documentation - https://router.vuejs.org/guide/advanced/typed-routes.html
We can define RouteNamedMap map and extends interface TypesConfig.
interface TypesConfig {
RouteNamedMap: /* your RouteNamedMap here */
}
It is very good, but... Some text from official documentation:
Here is an example of how to manually configure typed routes: ... TIP. This is indeed tedious and error-prone.
And it's true. Writing bulky types that duplicate your routes array is very tedious. Just look on it:
{
'posts/:id': RouteRecordInfo<
'posts-item',
'/:name/:id',
{ name: number },
{ name: string },
never
>
}
Cumbersome, inconvenient, lazy... And in this case there are no child routes yet...
The official documentation advises us to use route and type generation based on the unplugin-vue-router library. Of course, it is great tool, but it is file based Routing. Not everyone likes this option.
That's why we made a library that will turn your routes into types!
Of course, don't forget about
npm i vue-routes-to-types
// import types
import type { GenerateRoutesMap, NamedRouteRecordRaw } from "vue-routes-to-types";
// Create routes in usual way. But mark this array as const
const routes = [
{
path: '/',
name: 'home',
component: () => ''
},
{
path: '/item/:id',
name: 'item',
component,
children: [
{
path: 'theme/:some',
name: 'item-some',
component: () => ''
}
]
}
] as const satisfies NamedRouteRecordRaw[];
// build types with our magic
export type RoutesMap = GenerateRoutesMap<typeof routes>;
declare module 'vue-router' {
interface TypesConfig {
RouteNamedMap: RoutesMap
}
}
It is RouteRecordRaw from vue-router with small modifications.
- Route name field is required now
- Route children is RouteRecordRaw[] of course
- Redirect and props is simplified. In RouteRecordRaw these fields use RouteNamedMap which results in a circular type dependency.
- Automaticly generates RouteRecordInfo for each NamedRouteRecordRaw
- Correctly parse dynamic params
- Supports children routes
- Correctly joins parent and children dynamic params
- Trys to detect popular number patterns
- Allows you to set up custom number detection logic
- Detects optional params
- Detects repeatable params
- Creates great tuple type if repeatable params is required: [T,...T[]] instead of T[]
- Of course we can`t really analize RegExp in () of dynamic param. We just try to detect \\d or \\d+. But your can provide custom number detectors.
- You can`t use typed routing into routes array. As sample, when you define redirect field system does not know about types yet.
<RouterLink :to="{ name: 'some '}">
does not show error even if params is required. It is bad and it is question for vue-router team. They marked params as optional for all cases.- If you like very illogical patterns like /compare/:parts(\d*)+ libruary can`t help.
By default we try to detected numbers based on
export type DefaultNumberDetectors = ['\\d', '\\d+']
Your can provide custom number detectors as the second param of GenerateRoutesMap
export type RoutesMap = GenerateRoutesMap<
typeof routes,
['\\d', '\\d+', '\\d{4}']
>;
Now url like '/archive/:year(\\d{4})' infer rawParams = { year: number }
For this sample real rawParams is good = [number, ...number[]].
But result of vue-router useRoute() is... strange... If repeateable param with * is not provided, useRoute return empty string, not empty array.
That is, here our library simply adapts to the logic of vue-router.
If you know typescript just open tests folder and learns files in right order:
- meta
- parser
- draft
- combine
- custom-number-detectors