TypeScript Academy · Урок

Пользовательские хуки с обобщениями и выводом типов

Пишите повторно используемые пользовательские хуки с для значений, результатов и ошибок; применяйте вывод типов и ограничения для безопасных API.

Урок 1 из 28 шагов

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

Введение

Цель: создать обобщённые хуки, которые ощущаются как встроенные: типизированный хук для localStorage, асинхронный загрузчик и помощник для управляемого и неуправляемого режимов. Вы будете полагаться на вывод типов, поэтому вызывающему коду редко понадобятся аннотации.

  • Возвращать кортежи для удобства в стиле React
  • Использовать ограничения при необходимости
  • Не использовать универсальный тип

useLocalStorage<T>

Возвращайте кортеж [значение, set], как в useState. Поддерживайте согласованность T между значением и функцией установки.

import { useEffect, useState } from "react"

export function useLocalStorage<T>(key: string, initial: T): [T, (v: T | ((prev: T) => T)) => void] {
  const [value, setValue] = useState<T>(() => {
    try {
      const raw = localStorage.getItem(key)
      return raw ? (JSON.parse(raw) as T) : initial
    } catch {
      return initial
    }
  })

  useEffect(() => {
    try { localStorage.setItem(key, JSON.stringify(value)) } catch {}
  }, [key, value])

  const set = (v: T | ((prev: T) => T)) => {
    setValue(prev => (typeof v === "function" ? (v as (p: T) => T)(prev) : v))
  }

  return [value, set]
}

// Usage
// const [user, setUser] = useLocalStorage("user", { id: 1, name: "Ada" })

useAsync<T>

Возвращайте объект со свойствами значение, ошибка, загрузка. Тип значения выводится из промиса, возвращаемого fn.

import { useEffect, useState } from "react"

export function useAsync<T>(fn: () => Promise<T>, deps: unknown[] = []) {
  const [value, setValue] = useState<T | null>(null)
  const [error, setError] = useState<unknown>(null)
  const [loading, setLoading] = useState<boolean>(false)

  useEffect(() => {
    let cancelled = false
    setLoading(true)
    fn().then(
      (v) => { if (!cancelled) { setValue(v); setError(null) } },
      (e) => { if (!cancelled) { setError(e); setValue(null) } }
    ).finally(() => { if (!cancelled) setLoading(false) })
    return () => { cancelled = true }
  }, deps)

  return { value, error, loading }
}

// Usage
// const { value, error, loading } = useAsync(() => fetch("/api").then(r => r.json()))

useControlled<T>

Поддерживайте управляемый и неуправляемый режимы с помощью одного помощника. Кортеж сохраняет согласованность T.

import { useState } from "react"

type ControlledProps<T> = {
  value?: T
  defaultValue: T
  onChange?: (v: T) => void
}

export function useControlled<T>({ value, defaultValue, onChange }: ControlledProps<T>): [T, (v: T) => void] {
  const [inner, setInner] = useState<T>(defaultValue)
  const isControlled = value !== undefined
  const current = isControlled ? (value as T) : inner
  const set = (v: T) => { isControlled ? onChange?.(v) : setInner(v) }
  return [current, set]
}

// Usage
// const [v, setV] = useControlled({ value, defaultValue: "", onChange: setValue })

Вывод типов и ограничения

Предпочитайте вывод типов из аргументов; добавляйте ограничения extends только тогда, когда хуку нужны определённые поля.

// Inference works from the initial value
const [settings, setSettings] = useLocalStorage("settings", { theme: "dark", pageSize: 20 })
// T = { theme: string; pageSize: number }

// Constrain T when needed
interface WithId { id: string }
function useById<T extends WithId>(items: T[], id: string) {
  return items.find(x => x.id === id) || null
}

// Usage
const user = useById([{ id: "u1", name: "Ada" }], "u1")

Советы

Советы:

  • Возвращайте кортежи для удобства в стиле React и единообразной типизации.
  • Никогда не используйте any в общедоступных сигнатурах хуков.
  • Принимайте функции обновления (prev) => next для удобных переходов состояния.

Проверка типизации хуков

Быстрая проверка: какая сигнатура лучше всего подходит для обобщённого хука localStorage?

Повторение

Повторение: вы создали обобщённые хуки, использующие вывод типов, применяющие ограничения только при необходимости и предоставляющие результаты в виде кортежей или объектов, подобно встроенным API React.

Можно начать бесплатно

Изучай TypeScript с ИИ-репетитором — бесплатно

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

Курсы
101
Уроки
352

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

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

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

Чему я научусь в уроке «Пользовательские хуки с обобщениями и выводом типов»?

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

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

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

Сколько времени занимает урок «Пользовательские хуки с обобщениями и выводом типов»?

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

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

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

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

  1. Пользовательские хуки с обобщениями и выводом типов
  2. Типы Suspense и границ ошибок
← Назад к TypeScript Academy