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, когда библиотечный код требует точного описания форм данных. Главное правило: дженерик должен делать код безопаснее и читаемее, а не наоборот.

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

    Комментарии

    0

    Постройте личный план изучения Nuxt - fullstack Vue фреймворк до уровня Middle — бесплатно!

    Nuxt - fullstack Vue фреймворк — часть карты развития Frontend

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

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

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

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

    Основы разработки

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга5.0
    бесплатно
    Подробнее
    изображение курса

    Angular

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

    Feature-Sliced Design

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

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

    Картинка поста Паттерны проектирования на TypeScript: SOLID с примерами
    Иконка аватараАнтон
    Иконка календаря13 июня 2026
    typescriptsolidпаттерны проектирования+ 2middleИконка уровня middle

    Паттерны проектирования на TypeScript: SOLID с примерами

    Паттерны проектирования на TypeScript и принципы SOLID: разбор каждого принципа с практическими примерами кода, типичными ошибками и рекомендациями.

    Иконка чипа0
    Иконка глаза52
    Иконка комментариев0
    Картинка поста Микрофронтенды и Module Federation: когда применять и как внедрить
    Иконка аватараАнтон
    Иконка календаря28 мая 2026
    микрофронтендыmodule federationwebpack+ 2seniorИконка уровня senior

    Микрофронтенды и Module Federation: когда применять и как внедрить

    Микрофронтенды и Module Federation: разбираем когда нужна такая архитектура, как настроить host и remote приложения и избежать типичных ошибок.

    Иконка чипа+1
    Иконка глаза218
    Иконка комментариев0
    Картинка поста GraphQL с нуля: схемы, резолверы и интеграция с React
    Иконка аватараАнтон
    Иконка календаря14 июня 2026
    GraphQLReactApollo Client+ 2middleИконка уровня middle

    GraphQL с нуля: схемы, резолверы и интеграция с React

    GraphQL с нуля: разбираем схемы, резолверы и интеграцию с React через Apollo Client. Практические примеры запросов, мутаций и подписок.

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