Vue Router и TypeScript

Vue Router предоставляет удобный механизм маршрутизации для приложений на Vue.js. При работе с TypeScript важно учитывать типизацию маршрутов и компонентов, что повышает надежность и предсказуемость кода.

Настройка проекта

Для начала требуется установить Vue Router и соответствующие типы:

npm install vue-router@next
npm install --save-dev @types/vue-router

Создание маршрутизатора в TypeScript требует явного указания типов для массива маршрутов и экземпляра маршрутизатора:

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import Home from './views/Home.vue';
import About from './views/About.vue';

const routes: Array<RouteRecordRaw> = [
  { path: '/', name: 'Home', component: Home },
  { path: '/about', name: 'About', component: About }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;

Здесь RouteRecordRaw обеспечивает строгую типизацию маршрутов, предотвращая ошибки при указании компонентов или путей.

Типизация параметров маршрутов

При работе с динамическими сегментами пути TypeScript позволяет безопасно получать параметры маршрута через useRoute:

import { useRoute } from 'vue-router';

export default {
  setup() {
    const route = useRoute();
    const id = route.params.id as string;

    return { id };
  }
}

Использование as string гарантирует, что параметр будет интерпретирован как строка, предотвращая ошибки типов.

Программная навигация с типизацией

router.push и router.replace поддерживают строгую типизацию объектов маршрутов:

import { useRouter } from 'vue-router';

export default {
  setup() {
    const router = useRouter();

    function goToAbout() {
      router.push({ name: 'About' });
    }

    function goToUser(id: number) {
      router.push({ name: 'User', params: { id } });
    }

    return { goToAbout, goToUser };
  }
}

Типизация имени маршрута и параметров обеспечивает автодополнение и предотвращает ошибки при вводе строк вручную.

Защита маршрутов и типы Guard

Vue Router позволяет использовать охранников маршрутов (navigation guards) с полной поддержкой TypeScript:

import { NavigationGuardNext, RouteLocationNormalized } from 'vue-router';

function authGuard(
  to: RouteLocationNormalized,
  from: RouteLocationNormalized,
  next: NavigationGuardNext
) {
  const isAuthenticated = false; // логика проверки
  if (isAuthenticated) {
    next();
  } else {
    next({ name: 'Home' });
  }
}

const routes: Array<RouteRecordRaw> = [
  { path: '/dashboard', name: 'Dashboard', component: () => import('./views/Dashboard.vue'), beforeEnter: authGuard }
];

Типы RouteLocationNormalized и NavigationGuardNext позволяют безопасно работать с маршрутами и объектами навигации.

Lazy-loading и динамический импорт компонентов

Для оптимизации загрузки компонентов используется динамический импорт с указанием типа:

const User = () => import('./views/User.vue') as Promise<typeof import('*.vue')>;

const routes: Array<RouteRecordRaw> = [
  { path: '/user/:id', name: 'User', component: User }
];

Типизация Promise<typeof import('*.vue')> позволяет TypeScript корректно выводить типы для компонента при ленивой загрузке.

Расширение интерфейса RouteMeta

Vue Router поддерживает пользовательские метаданные через meta, которые можно типизировать:

declare module 'vue-router' {
  interface RouteMeta {
    requiresAuth?: boolean;
  }
}

const routes: Array<RouteRecordRaw> = [
  { path: '/profile', name: 'Profile', component: () => import('./views/Profile.vue'), meta: { requiresAuth: true } }
];

Расширение RouteMeta позволяет безопасно использовать метаданные, избегая ошибок при доступе к ним.

Использование Vue Router с Composition API

В Composition API маршрутизатор и параметры маршрутов доступны через useRouter и useRoute с полной поддержкой типов:

import { useRouter, useRoute } from 'vue-router';

export default {
  setup() {
    const router = useRouter();
    const route = useRoute();

    function navigateToProfile(userId: string) {
      router.push({ name: 'Profile', params: { id: userId } });
    }

    const currentUserId = route.params.id as string;

    return { navigateToProfile, currentUserId };
  }
}

Подход позволяет объединять строгую типизацию с гибкой навигацией в приложении.

Typed маршруты и создание утилит

Для крупных проектов рекомендуется создать типизированный объект с именами маршрутов, чтобы избежать ошибок при указании строковых значений:

export const RouteNames = {
  Home: 'Home',
  About: 'About',
  Profile: 'Profile'
} as const;

router.push({ name: RouteNames.Profile, params: { id: '123' } });

as const фиксирует значения, позволяя TypeScript использовать их как литеральные типы, что повышает безопасность кода.

Работа с query-параметрами

Query-параметры также можно типизировать, обеспечивая контроль типов:

interface SearchQuery {
  term?: string;
  page?: number;
}

function search(query: SearchQuery) {
  router.push({ name: 'Search', query: { term: query.term, page: String(query.page ?? 1) } });
}

Преобразование типов и явная типизация query-параметров предотвращают ошибки при чтении или записи данных.

Итоговая организация

Типизированная интеграция Vue Router с TypeScript включает:

  • использование RouteRecordRaw для маршрутов,
  • явную типизацию параметров через useRoute,
  • строгую типизацию навигации с router.push и router.replace,
  • типизированные охранники маршрутов и метаданные RouteMeta,
  • ленивую загрузку компонентов с типами,
  • централизованное хранение имен маршрутов для предотвращения ошибок строковых литералов.

Такой подход обеспечивает надежность, удобство автодополнения и предупреждает распространённые ошибки при разработке крупных SPA на Vue 3 с TypeScript.