0Pricing
React Academy · Урок

Типизация контекста и пользовательских хуков

Создавайте типизированный контекст со значениями по умолчанию и пишите пользовательские хуки с явными возвращаемыми типами.

«Типизация контекста и пользовательских хуков» — бесплатный урок React Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения React Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс React Academy содержит 4 уроков всего.

Типизированный контекст с createContext

Передайте тип контекста и значение по умолчанию в createContext. Используйте null по умолчанию, если контекст должен применяться внутри провайдера, и обрабатывайте этот случай с помощью проверки.

interface AuthContextType {
  user: User | null;
  login: (credentials: Credentials) => Promise<void>;
  logout: () => void;
}

const AuthContext = createContext<AuthContextType | null>(null);

Шаблон проверочного хука

Создайте пользовательский хук, который читает контекст и выдаёт ошибку, если его используют за пределами провайдера. Это устраняет проверки на null в каждом месте вызова.

export function useAuth(): AuthContextType {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error('useAuth must be used within AuthProvider');
  return ctx;
}

Типизация провайдера

Компонент-провайдер оборачивает дочерние элементы и предоставляет значение контекста. Явно типизируйте объект значения, чтобы TypeScript проверял его соответствие типу контекста.

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null);

  const login = async (creds: Credentials) => {
    const u = await apiLogin(creds);
    setUser(u);
  };

  const logout = () => setUser(null);

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

Контекст со значением по умолчанию

Если существует подходящее значение по умолчанию, например тема, передайте его непосредственно в createContext, чтобы контекст никогда не был равен null и проверочный хук не требовался.

interface ThemeContextType { theme: 'light' | 'dark'; toggle: () => void; }

const ThemeContext = createContext<ThemeContextType>({
  theme: 'light',
  toggle: () => {},
});

export const useTheme = () => useContext(ThemeContext);

Типизация возвращаемых значений пользовательских хуков

Явно аннотируйте возвращаемый тип пользовательских хуков или позвольте TypeScript вывести его. Явные типы служат документацией и предотвращают случайное изменение формы результата.

interface UseCounterReturn {
  count: number;
  increment: () => void;
  decrement: () => void;
  reset: () => void;
}

function useCounter(initial = 0): UseCounterReturn {
  const [count, setCount] = useState(initial);
  return {
    count,
    increment: () => setCount(c => c + 1),
    decrement: () => setCount(c => c - 1),
    reset: () => setCount(initial),
  };
}

Кортежные типы возвращаемых значений

Хуки, возвращающие пару, как useState, используют кортежи. Типизируйте их с помощью as const или явного типа кортежа, чтобы деструктуризация выполнялась корректно.

function useToggle(initial = false): [boolean, () => void] {
  const [value, setValue] = useState(initial);
  const toggle = useCallback(() => setValue(v => !v), []);
  return [value, toggle];
}

// Destructuring correctly infers types:
const [isOpen, toggleOpen] = useToggle();

Обобщённые пользовательские хуки

Пользовательские хуки тоже могут быть обобщёнными. Обобщённый хук useLocalStorage хранит сериализуемые значения любого типа с полной типобезопасностью.

function useLocalStorage<T>(key: string, initialValue: T): [T, (val: T) => void] {
  const [stored, setStored] = useState<T>(() => {
    try {
      const item = localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch { return initialValue; }
  });

  const setValue = (val: T) => {
    setStored(val);
    localStorage.setItem(key, JSON.stringify(val));
  };

  return [stored, setValue];
}

Типизация useReducer

Определяйте типы действий как размеченные объединения, а форму состояния — как интерфейс. TypeScript будет проверять допустимость типов действий в редьюсере.

interface State { count: number; status: 'idle' | 'loading'; }
type Action =
  | { type: 'INCREMENT' }
  | { type: 'SET_STATUS'; payload: State['status'] };

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'INCREMENT': return { ...state, count: state.count + 1 };
    case 'SET_STATUS': return { ...state, status: action.payload };
  }
}

const [state, dispatch] = useReducer(reducer, { count: 0, status: 'idle' });

Типизация useCallback и useMemo

TypeScript выводит типы для useCallback и useMemo из фабричной функции. Добавляйте явные аннотации только в случае ошибки вывода типов.

const handleChange = useCallback(
  (e: React.ChangeEvent<HTMLInputElement>) => {
    onChange(e.target.value);
  },
  [onChange]
);

const sorted = useMemo(
  () => [...items].sort((a, b) => a.name.localeCompare(b.name)),
  [items]
); // inferred as typeof items

Шаблон селектора контекста с типами

Типизированный хук-селектор принимает функцию-селектор и возвращает только нужную часть данных, сохраняя полный вывод типов.

function useAuthSelector<T>(selector: (ctx: AuthContextType) => T): T {
  const ctx = useAuth();
  return selector(ctx);
}

// Usage — TypeScript infers User | null:
const user = useAuthSelector(ctx => ctx.user);

Избегайте неограниченной типизации в хуках

Никогда не используйте any в пользовательских хуках. Применяйте обобщённые типы, unknown с проверками типов или конкретные интерфейсы, чтобы сохранять целостность цепочки типов.

// Bad:
function useFetch(url: string): { data: any; loading: boolean } { ... }

// Good:
function useFetch<T>(url: string): { data: T | null; loading: boolean } {
  const [data, setData] = useState<T | null>(null);
  // ...
  return { data, loading };
}

Быстрая проверка

Какова цель шаблона проверочного хука при типизации контекста React?

Повторение

Типизируйте контекст с помощью явного интерфейса и хука, проверяющего значение на null. Аннотируйте возвращаемые типы пользовательских хуков интерфейсами или типами кортежей, используйте обобщённые типы для повторно используемых хуков и типизируйте useReducer размеченными объединениями действий, чтобы выявлять недопустимые отправки во время компиляции.

Часто задаваемые вопросы

Урок «Типизация контекста и пользовательских хуков» бесплатный?

Да — полный текст урока «Типизация контекста и пользовательских хуков» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс React Academy, подпишись на CoddyKit PRO. Курс React Academy содержит 4 уроков всего.

Чему я научусь в уроке «Типизация контекста и пользовательских хуков»?

Создавайте типизированный контекст со значениями по умолчанию и пишите пользовательские хуки с явными возвращаемыми типами. Ты практикуешь React Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать React Academy?

Предыдущий опыт не требуется. React Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Типизация контекста и пользовательских хуков»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке React Academy?

Да. Каждый урок React Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Типизация свойств и возвращаемых типов компонентов
  2. Типизация событий и ссылок в TypeScript
  3. Обобщённые компоненты и вспомогательные типы
  4. Типизация контекста и пользовательских хуков
← Назад к React Academy