Skip to content

Type-Safe Routing

Kimesh generates TypeScript definitions for your routes, providing full type safety for navigation and params.

Generated Types

When you run the development server, Kimesh generates type definitions in .kimesh/typed-routes.d.ts:

ts
// Auto-generated route types
export interface RouteNamedMap {
  index: RouteRecordInfo<'index', '/', {}, {}>
  about: RouteRecordInfo<'about', '/about', {}, {}>
  posts: RouteRecordInfo<'posts', '/posts', {}, {}>
  'posts-postId': RouteRecordInfo<'posts-postId', '/posts/:postId', { postId: string | number }, { postId: string }>
}

Type-Safe Navigation

The KmLink component provides type-safe navigation:

template
<script setup lang="ts">
import { KmLink } from '@kimesh/router-runtime'
</script>

<template>
  <!-- Type-safe route with params -->
  <KmLink to="/posts/:postId" :params="{ postId: post.id }">
    {{ post.title }}
  </KmLink>

  <!-- Simple route without params -->
  <KmLink to="/about">About</KmLink>
</template>

Using useNavigate

Navigate programmatically with type checking:

ts
import { useNavigate } from '@kimesh/router-runtime'

const navigate = useNavigate()

function goToPost(id: string) {
  navigate('/posts/:postId', { params: { postId: id } })
}

function goHome() {
  navigate('/')
}

Using useRouter

Standard Vue Router navigation:

ts
import { useRouter } from '@kimesh/router-runtime'

const router = useRouter()

function navigateToPost(id: string) {
  router.push({ name: 'posts-postId', params: { postId: id } })
}

Route Params

useParams

Access current route params:

ts
import { useParams } from '@kimesh/router-runtime'

// Non-reactive, use for initial values
const params = useParams<'/posts/:postId'>()
console.log(params.postId) // string

useReactiveParams

Reactive params that update on navigation:

ts
import { useReactiveParams } from '@kimesh/router-runtime'

// Reactive - updates when route changes
const params = useReactiveParams<'/posts/:postId'>()

// Use .value to access
console.log(params.value.postId)

Param Types

Different param patterns generate different types:

File PatternURL PatternType
$id.vue:idstring
$id/ (directory):idstring
$.vue:pathMatch(.*)*string[]

Search Params

useSearch

Access and manipulate typed search/query params:

ts
import { useSearch } from '@kimesh/router-runtime'
import { z } from 'zod'

const searchSchema = z.object({
  page: z.coerce.number().default(1),
  sort: z.enum(['asc', 'desc']).default('desc'),
})

const { search, setSearch, setAllSearch, resetSearch } = useSearch(searchSchema)

// Read validated values
console.log(search.value.page) // number (not string!)

// Update single param (updates URL)
setSearch('page', 2)

// Update multiple params
setAllSearch({ page: 1, sort: 'asc' })

// Reset to defaults
resetSearch()

Validation with Zod

Use validateSearch in createFileRoute for validated search params:

ts
import { createFileRoute } from '@kimesh/router-runtime'
import { z } from 'zod'

const searchSchema = z.object({
  page: z.coerce.number().default(1),
  sort: z.enum(['newest', 'oldest']).default('newest'),
  tag: z.string().optional(),
})

export const Route = createFileRoute('/posts')({
  validateSearch: searchSchema,
  loader: async ({ search, context }) => {
    // search is typed as { page: number, sort: 'newest' | 'oldest', tag?: string }
    console.log(search.page) // number, not string
  },
})

Type Utilities

RouteNames

Get all valid route names:

ts
import type { RouteNames } from '@kimesh/router-runtime'

// RouteNames = 'index' | 'about' | 'posts' | 'posts-postId' | ...
function logRoute(name: RouteNames) {
  console.log(`Navigating to ${name}`)
}

RouteParams<T>

Get params type for a specific route:

ts
import type { RouteParams } from '@kimesh/router-runtime'

type PostParams = RouteParams<'posts-postId'>
// PostParams = { postId: string }

RoutePath<T>

Get the path template for a route:

ts
import type { RoutePath } from '@kimesh/router-runtime'

type PostPath = RoutePath<'posts-postId'>
// PostPath = '/posts/:postId'

HasParams<T>

Check if a route has params:

ts
import type { HasParams } from '@kimesh/router-runtime'

type IndexHasParams = HasParams<'index'> // false
type PostHasParams = HasParams<'posts-postId'> // true

Loader Type Safety

Type your loaders with generic params:

ts
// In your route file's <script lang="ts"> block
import { createFileRoute } from '@kimesh/router-runtime'
import { postDetailQuery } from './posts.data'

export const Route = createFileRoute('/posts/:postId')({
  loader: async ({ params, context }) => {
    // params.postId is typed as string
    await context.queryClient.ensureQueryData(postDetailQuery(params.postId))
  },
})

IDE Support

VS Code

Install the Vue - Official extension for:

  • Route path autocomplete in KmLink
  • Param type checking
  • Jump to route file definition

TypeScript Configuration

Ensure your tsconfig.json includes the generated types:

json
{
  "compilerOptions": {
    "strict": true,
    "moduleResolution": "bundler"
  },
  "include": ["src/**/*.ts", "src/**/*.vue", ".kimesh/**/*.ts"]
}

Released under the MIT License.