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

Як типізувати provide/inject через InjectionKey і чому рядкові ключі погані?

provide/inject передає значення від предка до будь-якого нащадка без прокидання через props. З рядковим ключем TypeScript не знає, що там лежить:

provide('theme', theme)
const theme = inject('theme')   // unknown - і помилка в назві ключа ніде не підсвітиться

InjectionKey<T> - символ, що несе тип значення:

// keys.ts
import type { InjectionKey, Ref } from 'vue'

export interface ThemeContext {
  mode: Ref<'light' | 'dark'>
  toggle: () => void
}

export const ThemeKey: InjectionKey<ThemeContext> = Symbol('theme')
// провайдер
provide(ThemeKey, { mode, toggle })   // TypeScript перевірить форму значення

// споживач
const theme = inject(ThemeKey)        // ThemeContext | undefined

Чому undefined у типі: компонент може опинитися поза деревом провайдера - тоді inject поверне undefined (з попередженням у режимі розробки). Варіанти:

const theme = inject(ThemeKey, defaultTheme)      // значення за замовчуванням

function useTheme(): ThemeContext {
  const theme = inject(ThemeKey)
  if (!theme) throw new Error('useTheme() потрібно викликати всередині ThemeProvider')
  return theme
}

Обгортка-composable з явною помилкою - найпрактичніший варіант: зрозуміле повідомлення замість Cannot read properties of undefined десь глибоко.

Чому символ кращий за рядок:

  • немає зіткнень: дві бібліотеки з ключем 'theme' перезапишуть одна одну; символи завжди унікальні;
  • тип прив'язаний до ключа - не треба дублювати тип у кожному inject;
  • рефакторинг і пошук працюють за імпортом ключа, а не за рядком.

Що надавати:

  • реактивні значення (ref, computed) - інакше нащадки не побачать змін;
  • функції для зміни замість відкритого змінюваного стану - провайдер контролює, як змінюється дані. Для захисту від прямої зміни - readonly(state).

Коли не provide/inject: глобальний стан застосунку (кошик, користувач) - Pinia з DevTools і плагінами. Provide/inject - для контексту піддерева: форма й її поля, таблиця й колонки, тема окремого віджета.

Докладніше в документації: TypeScript: типізація provide / inject

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

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