How to use

The module will automaticaly provide autocomplete and type-check for route path, name and params.

Params autocomplete takes into account the way vue-router works (As navigating between children routes without re-providing the param).

The types from vue-router and Nuxt navigation utils will be owerwritten, allowing for a safe navigation.

Examples for different pages structure

All those examples will be about files present in the pages folder.

Basic path navigation

Path navigation will propose you the list of routes declaration to choose from, and will dynamically validate the route. It supports

  • Query params
  • Hash params
  • Errors for invalid paths like /foo /bar or /foo////bar
For path autocomplete to work with <NuxtLink/> the following Volar settings are injected into your .nuxt/tsconfig:
  • jsxTemplates
  • experimentalRfc436

pages/login.vue

When a route has no params defined, the params property will not even be available as an option in the router.

router.push('/login/bar'); // Error! ❌
router.push({name: 'login', params: {foo: 'bar'}}) // Error! ❌

router.push('/login'); // Good! ✅
router.push({name: 'login'}) // Good! ✅

Same with resolved routes, the params property will not be available.

const route = useRoute();
if (route.name === 'login') {
  console.log(route.params); // Error! ❌
}

pages/user/[id].vue

When a route has a required param defined, navigating exactly to this route will throw an error if you don't provide a params property or if you put a wrong param.

router.push({name: 'user-id'}) // Error! ❌
router.push({name: 'user-id', params: {bar: 'baz'}}) // Error! ❌
router.push('/user') // Error! ❌

const id = "ey7878"
router.push(`/user/${id}`) // Good! ✅
router.push({name: 'user-id', params: {id}}) // Good! ✅

router.push(`/user/${id}/baguette`) // Error! ❌

For resolved routes, the params property will be available and correctly typed.

const route = useRoute();
if (route.name === 'foo') {
  console.log(route.params.baz); // Error! ❌
  console.log(route.params.foo); // Good! ✅
}
With useRoute, there is an additional guard that can save you some unecessary check if you're confident on the page you're in. See useRoute docs for more info

⬆️ Example:

const route = useRoute('foo');
console.log(route.params.baz); // Error! ❌
console.log(route.params.foo); // Good! ✅

pages/user/foo/[[bar]].vue

When a route has only an optional param defined, navigating exactly to this route will not require to provide a params property, and will mark the bar param as optional too.

router.push({name: 'user-foo-bar'}) // Good! ✅
router.push('/user/foo') // Good! ✅

router.push({name: 'user-foo-bar', params: {foo: 'baz'}}) // Error! ❌
router.push({name: 'user-foo-bar', params: {bar: 'baz'}}) // Good! ✅
router.push('/user/foo/baz') // Good! ✅

For resolved routes, the params property will be available and correctly typed.

const route = useRoute();
if (route.name === 'bar') {
  console.log(route.params.foo); // Error! ❌
  console.log(route.params.bar); // Good! ✅ - params: {bar?: string | undefined}
}

pages/[title]-[[slug]].vue

When a route has both a required and an optional param defined, navigating exactly to this route will require to provide a params property, and will mark the params accordingly.

router.push({name: 'title-slug'}) // Error! ❌

router.push({name: 'title-slug', params: {slug: 'baz'}}) // Error! ❌

router.push({name: 'title-slug', params: {title: 'Bonjour'}}) // Good! ✅

router.push({name: 'title-slug', params: {title: 'Bonjour', slug: 'baz'}}) // Good! ✅

router.push('/blabla-') // Good! ✅
router.push('/blabla-foo/bar') // Error! ❌

Fo resolved routes, the params property will be available and correctly typed.

const route = useRoute();
if (route.name === 'title-slug') {
  console.log(route.params.foo); // Error! ❌
  console.log(route.params.title); // Good! ✅ - title: string
  console.log(route.params.slug); // Good! ✅ - slug?: string | undefined
}

pages/[...options].vue

When you define a "catch-all" route, navigating exactly to this route will require to provide a params property, and will need the param the be an Array.

router.push({name: 'options'}) // Error! ❌
router.push({name: 'options', params: {options: 'baz'}}) // Error! ❌

router.push('/foo/bar/baz') // Good! ✅
router.push({name: 'options', params: {options: ['foo', 'bar']}}) // Good! ✅
router.push({name: 'options', params: {options: [1, 2, 3, 'foo']}}) // Good! ✅

For resolved routes, the params property will be available and correctly typed.

const route = useRoute();
if (route.name === 'options') {
  console.log(route.params.foo); // Error! ❌
  console.log(route.params.options.join(',')); // Good! ✅ - options: string[]
}

pages/nested/[title]/user/[id]/index.vue

On a route with nested params, the logic will be a little different. Because of vue-router behave, you are not required to re-provide parent params.
Ex: navigating from route
pages/nested/[title]/user/[id]/posts.vue -> pages/nested/[title]/user/[id]/index.vue, as [id] is a required param, you will not have to pass title and id params.

As we cannot know where you are navigating from, the title and id params will be optional.

router.push('/nested/foo/user') // Error! ❌
router.push({name: 'nested-title-user-id'}) // Error! ❌
router.push({name: 'nested-title-user-id', params: {foo: 'baz'}}) // Error! ❌

router.push('/nested/foo/user/YUEUY77') // Good! ✅
router.push({name: 'nested-title-user-id', params: {id: 1}}) // Good! ✅
router.push({name: 'nested-title-user-id', params: {id: 1, title: 'foo'}}) // Good! ✅

As for resolved routes, the parameters will not be marqued as optional

const route = useRoute();
if (route.name === 'nested-title-user-id') {
  console.log(route.params.foo); // Error! ❌
  console.log(route.params.id); // Good! ✅ - id: string
  console.log(route.params.title); // Good! ✅ - title: string
}