Перейти к основному содержимому
Модуль 3 · Урок 2 из 26/14 в курсе~15 min
Уроки модуля (2/2)

Фундаментальные дженерики

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


Общие функции

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

TS
function identity<T>(arg: T): T {
  return arg;
}

Буква T (сокращение от Type) является заполнителем для типа. Когда мы вызываем identity, TypeScript фиксирует тип переданного аргумента и автоматически присваивает T этот тип:

TS
const str = identity<string>('Hello'); // T is string
const num = identity(42); // T is number (automatically inferred!)

Общие интерфейсы и псевдонимы

Обобщенные шаблоны также можно применять к интерфейсам и псевдонимам типов для определения универсальных контейнеров или структур данных:

TS
interface Box<T> {
  content: T;
}

const stringBox: Box<string> = { content: 'TypeScript' };
const numberBox: Box<number> = { content: 42 };

Несколько параметров типа

Мы можем определить функции или типы, которые используют переменные нескольких типов (например, T и U):

TS
function mergeObjects<T, U>(obj1: T, obj2: U): T & U {
  return { ...obj1, ...obj2 };
}

Общие ограничения

Иногда мы хотим ограничить типы, принимаемые дженериком. Мы можем использовать ключевое слово extends, чтобы добавить ограничение.

Например, если мы хотим, чтобы универсальный тип всегда имел свойство length (например, строки или массивы):

TS
interface HasLength {
  length: number;
}

function logLength<T extends HasLength>(arg: T): void {
  console.log(arg.length); // Safe! We know arg has 'length'
}

logLength('Hello'); // Valid
logLength([1, 2, 3]); // Valid
// logLength(42); // Error: number does not have a length property!

Попробуйте сами

Упражнение 1. Общая функция идентификации

Упражнение#ts.m3.l2.e1
Попыток: 0Загрузка…

Завершите универсальную функцию идентификации так, чтобы она принимала параметр значения универсального типа T и возвращала его без изменений.

Загрузка редактора…
Показать подсказку

Тип возвращаемого значения должен быть того же универсального типа T, что и параметр.

Решение доступно после 3 попыток

Упражнение 2. Общая оболочка коробки

Упражнение#ts.m3.l2.e2
Попыток: 0Загрузка…

Определите универсальный интерфейс с именем Box, который принимает параметр типа T и имеет одно свойство с именем content типа T.

Загрузка редактора…
Показать подсказку

Используйте интерфейс Box<T> {content: T; } Синтаксис.

Решение доступно после 3 попыток

Упражнение 3. Общее ограничение

Упражнение#ts.m3.l2.e3
Попыток: 0Загрузка…

Напишите универсальную функцию с именем getLength, которая принимает параметр arg. arg должен быть ограничен интерфейсом, имеющим свойство длины (число). Функция должна возвращать arg.length.

Загрузка редактора…
Показать подсказку

Объявите функцию как getLength<T расширяет HasLength>(arg: T): число и верните arg.length.

Решение доступно после 3 попыток

Упражнение 4: Общая пара

Упражнение#ts.m3.l2.e4
Попыток: 0Загрузка…

Определите универсальный интерфейс Pair<T, U> с двумя свойствами: первое — типа T, второе — типа U. Затем создайте универсальную функцию makePair, которая принимает первое (типа T) и второе (типа U) и возвращает объект, реализующий Pair<T, U>.

Загрузка редактора…
Показать подсказку

Используйте синтаксис для двух общих параметров Pair<T, U> и определите makePair соответствующим образом.

Решение доступно после 3 попыток