Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як типізувати глобальні властивості й глобально зареєстровані компоненти у Vue?

Плагіни й app.config.globalProperties додають властивості, доступні в кожному компоненті ($t для перекладів, route() від Ziggy в Laravel-проєктах). Глобально зареєстровані компоненти (app.component('Icon', Icon)) доступні в усіх шаблонах без імпорту. TypeScript про них нічого не знає, поки їх не оголосити.

Глобальні властивості - розширення модуля vue:

// types/vue.d.ts
import type { route as routeFn } from 'ziggy-js'

export {}

declare module 'vue' {
  interface ComponentCustomProperties {
    route: typeof routeFn
    $t: (key: string, params?: Record<string, unknown>) => string
  }
}

Тепер у шаблоні {{ route('posts.show', post.id) }} і $t('cart.empty') мають типи, а друкарська помилка в назві - помилка vue-tsc.

Глобальні компоненти:

declare module 'vue' {
  interface GlobalComponents {
    Icon: typeof import('./components/Icon.vue')['default']
    Link: typeof import('@inertiajs/vue3')['Link']
  }
}

Розширення Vue - Official і vue-tsc перевіряють props таких компонентів у шаблонах так само, як імпортованих.

Важливі деталі:

  • файл оголошень має бути модулем (export {} чи будь-який імпорт/експорт), інакше declare module 'vue' замінить типи Vue замість розширення;
  • файл має потрапити в include у tsconfig;
  • бібліотеки (Vue Router, Pinia, Inertia) самі постачають такі розширення - $route, $router типізовані без ваших зусиль.

Краще уникати глобальних властивостей у Composition API. У <script setup> доступ до них через getCurrentInstance() - незручний і крихкий. Явний імпорт чи composable (const { t } = useI18n()) зрозуміліший, краще працює з tree shaking і тестами: у тесті достатньо замокати модуль, а не налаштовувати глобальні властивості.

Глобальні компоненти теж мають ціну: збирач не знає, чи вони використовуються, тож не може їх викинути чи винести в окрему частину. Реєструвати глобально варто лише справді повсюдні (іконка, посилання), решту - імпортувати там, де потрібні.

Докладніше в документації: TypeScript: розширення глобальних властивостей

Схожі питання