PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    TypeScript дженерики на практике: полный гайд для разработчиков

    TypeScript дженерики на практике: полный гайд для разработчиков

    Аватар автора TypeScript дженерики на практике: полный гайд для разработчиков

    Антон Ларичев

    Иконка календаря30 мая 2026
    typescriptgenericsjavascriptfrontendmiddleИконка уровня middle
    Картинка поста TypeScript дженерики на практике: полный гайд для разработчиков

    Введение

    TypeScript дженерики (generics) — один из самых мощных инструментов системы типов. Они позволяют писать переиспользуемый код, который работает с разными типами данных, сохраняя при этом строгую типизацию. Если функции и классы без дженериков жёстко привязаны к конкретным типам, то обобщённые конструкции принимают тип как параметр и возвращают результат, точно соответствующий входным данным.

    В этом гайде разберём синтаксис, ограничения (constraints), условные типы, утилитные дженерики и практические примеры, которые встречаются в реальной работе с React, Node.js и библиотеками вроде Axios или Prisma.

    Базовый синтаксис дженериков

    Простейший пример — функция, которая возвращает то, что в неё передали. Без дженериков пришлось бы либо использовать any и потерять типизацию, либо писать перегрузки для каждого типа.

    // Функция принимает значение типа T и возвращает то же T
    function identity<T>(value: T): T {
      return value;
    }
    
    // TypeScript сам выведет тип: number
    const num = identity(42);
    
    // Тип можно указать явно
    const str = identity<string>("hello");
    

    Дженерики можно использовать в интерфейсах, типах и классах:

    // Обобщённый интерфейс ответа API
    interface ApiResponse<T> {
      data: T;
      status: number;
      error: string | null;
    }
    
    // Конкретизация под пользователя
    type UserResponse = ApiResponse<{ id: number; name: string }>;
    

    Ограничения через extends

    Иногда нужно гарантировать, что тип-параметр обладает определённой структурой. Для этого применяется ключевое слово extends.

    // T должен иметь поле length
    function logLength<T extends { length: number }>(value: T): T {
      console.log(value.length);
      return value;
    }
    
    logLength("строка"); // ок, у строки есть length
    logLength([1, 2, 3]); // ок, у массива есть length
    // logLength(42); // ошибка: у number нет length
    

    Ещё полезный паттерн — получение типа ключа объекта через keyof:

    // K должен быть одним из ключей объекта T
    function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
      return obj[key];
    }
    
    const user = { id: 1, name: "Anna", role: "admin" };
    const name = getProperty(user, "name"); // тип string
    // getProperty(user, "email"); // ошибка: нет такого ключа
    

    Значения по умолчанию

    Для параметров типа можно задать значение по умолчанию — как для обычных аргументов функций. Это упрощает работу с обобщёнными компонентами.

    // По умолчанию состояние — пустой объект
    interface State<T = Record<string, unknown>> {
      loading: boolean;
      data: T;
    }
    
    // Без явного указания типа
    const initial: State = { loading: false, data: {} };
    

    Условные типы и infer

    Условные типы выглядят как тернарный оператор, но работают на уровне типов. Они особенно полезны в сочетании с infer — для извлечения вложенных типов.

    // Извлекаем тип элемента массива
    type ElementOf<T> = T extends Array<infer U> ? U : never;
    
    type Numbers = ElementOf<number[]>; // number
    type Mixed = ElementOf<(string | boolean)[]>; // string | boolean
    

    Типичный сценарий — получение типа возвращаемого значения функции (это встроенный ReturnType):

    // Реализация ReturnType вручную
    type MyReturnType<T extends (...args: any[]) => any> = 
      T extends (...args: any[]) => infer R ? R : never;
    
    function fetchUser() {
      return { id: 1, name: "Bob" };
    }
    
    type User = MyReturnType<typeof fetchUser>; // { id: number; name: string }
    

    Утилитные дженерики

    TypeScript предоставляет набор встроенных обобщённых типов, которые покрывают большинство задач трансформации.

    interface Article {
      id: number;
      title: string;
      body: string;
      publishedAt: Date;
    }
    
    // Все поля становятся необязательными
    type ArticleDraft = Partial<Article>;
    
    // Только нужные поля
    type ArticlePreview = Pick<Article, "id" | "title">;
    
    // Все поля кроме указанных
    type ArticleWithoutDate = Omit<Article, "publishedAt">;
    
    // Делает все поля обязательными
    type StrictArticle = Required<Article>;
    

    Практический пример: типобезопасный fetch

    Соберём небольшую обёртку над fetch, которая возвращает данные нужного типа без приведения через as.

    // Обобщённая функция запроса
    async function apiGet<T>(url: string): Promise<T> {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      return response.json() as Promise<T>;
    }
    
    // Использование с указанием формы ответа
    interface Post {
      id: number;
      title: string;
    }
    
    const posts = await apiGet<Post[]>("/api/posts");
    posts[0].title; // автодополнение и проверка типов
    

    Дженерики в React-компонентах

    Обобщённые компоненты помогают строить переиспользуемые списки, таблицы и селекты без потери типизации элементов.

    // Список с произвольным типом элементов
    interface ListProps<T> {
      items: T[];
      renderItem: (item: T) => React.ReactNode;
    }
    
    function List<T>({ items, renderItem }: ListProps<T>) {
      return <ul>{items.map((item, i) => <li key={i}>{renderItem(item)}</li>)}</ul>;
    }
    
    // item автоматически имеет тип { id: number; name: string }
    <List
      items={[{ id: 1, name: "Anna" }]}
      renderItem={(item) => item.name}
    />;
    

    Частые ошибки

    Чрезмерное обобщение. Не каждой функции нужны дженерики. Если параметр типа используется только один раз и не влияет на возврат — это просто шум. Заменяйте таким случаем обычным типом.

    Использование any вместо ограничений. Конструкция <T extends any> или T = any обнуляет пользу от обобщения. Применяйте unknown, если действительно не знаете тип, или задавайте осмысленные ограничения через extends.

    Игнорирование вывода типов. TypeScript умеет выводить параметры из аргументов. Явное указание identity<string>("x") избыточно, если компилятор сам справляется. Это засоряет код.

    Путаница с keyof и значением ключа. Тип T[K] — это тип значения, а не строки ключа. Помните, что ключ остаётся литералом, а через индексный доступ вы получаете именно поле.

    Дженерик вместо union. Если функция принимает строго два варианта типа, перегрузки или union читаются понятнее, чем обобщение.

    Заключение

    Дженерики превращают TypeScript из строгого, но негибкого языка в выразительный инструмент моделирования данных. Они позволяют описать связь между входом и выходом функции, между состоянием и его трансформациями, между ключом объекта и типом значения. Начните с простых случаев — обёрток над API, утилит для коллекций, компонентов-списков — и постепенно подключайте условные типы и infer, когда библиотечный код требует точного описания форм данных. Главное правило: дженерик должен делать код безопаснее и читаемее, а не наоборот.

    Иконка глаза723

    Комментарии

    0

    Постройте личный план изучения React state менеджер Zustand до уровня Middle — бесплатно!

    React state менеджер Zustand — часть карты развития Frontend

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Vue 3 и Pinia

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Next.js - с нуля

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.7
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Feature-Sliced Design

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.5
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста GraphQL vs REST: что выбрать для API в 2026 году
    Иконка аватараАнтон
    Иконка календаря11 июля 2026
    graphqlrestapi+ 3middleИконка уровня middle

    GraphQL vs REST: что выбрать для API в 2026 году

    GraphQL vs REST — разбираем ключевые отличия, сценарии применения и подводные камни каждого подхода, чтобы выбрать правильный инструмент для вашего проекта.

    Иконка чипа0
    Иконка глаза130
    Иконка комментариев0
    Картинка поста Тестирование React-компонентов с React Testing Library
    Иконка аватараАнтон
    Иконка календаря07 июля 2026
    reacttestingreact-testing-library+ 2middleИконка уровня middle

    Тестирование React-компонентов с React Testing Library

    React Testing Library — инструмент для тестирования React-компонентов через поведение пользователя, а не детали реализации. Примеры, паттерны, частые ошибки.

    Иконка чипа0
    Иконка глаза192
    Иконка комментариев0
    Картинка поста Clean Architecture: чистая архитектура для веб-разработки
    Иконка аватараАнтон
    Иконка календаря02 июля 2026
    архитектураclean architecturetypescript+ 3middleИконка уровня middle

    Clean Architecture: чистая архитектура для веб-разработки

    Clean Architecture разделяет код на независимые слои: бизнес-логика не зависит от фреймворков, БД и внешних сервисов. Разбираем на примерах TypeScript.

    Иконка чипа0
    Иконка глаза236
    Иконка комментариев0
    Иконка чипа0