Уроки модуля (2/2)
Фундаментальные дженерики
Дженериксы (общее программирование) — одна из самых мощных функций TypeScript. Они позволяют вам писать гибкие, повторно используемые компоненты, функции и интерфейсы, которые могут работать с разными типами данных, сохраняя при этом максимальную безопасность типов и избегая использования any.
Общие функции
Думайте об обобщении как о переменной для типов. Давайте рассмотрим функцию, которая возвращает значение, переданное ей в качестве аргумента:
function identity<T>(arg: T): T {
return arg;
}Буква T (сокращение от Type) является заполнителем для типа. Когда мы вызываем identity, TypeScript фиксирует тип переданного аргумента и автоматически присваивает T этот тип:
const str = identity<string>('Hello'); // T is string
const num = identity(42); // T is number (automatically inferred!)Общие интерфейсы и псевдонимы
Обобщенные шаблоны также можно применять к интерфейсам и псевдонимам типов для определения универсальных контейнеров или структур данных:
interface Box<T> {
content: T;
}
const stringBox: Box<string> = { content: 'TypeScript' };
const numberBox: Box<number> = { content: 42 };Несколько параметров типа
Мы можем определить функции или типы, которые используют переменные нескольких типов (например, T и U):
function mergeObjects<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}Общие ограничения
Иногда мы хотим ограничить типы, принимаемые дженериком. Мы можем использовать ключевое слово extends, чтобы добавить ограничение.
Например, если мы хотим, чтобы универсальный тип всегда имел свойство length (например, строки или массивы):
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. Общая функция идентификации
Завершите универсальную функцию идентификации так, чтобы она принимала параметр значения универсального типа T и возвращала его без изменений.
Показать подсказку
Тип возвращаемого значения должен быть того же универсального типа T, что и параметр.
Решение доступно после 3 попыток
Упражнение 2. Общая оболочка коробки
Определите универсальный интерфейс с именем Box, который принимает параметр типа T и имеет одно свойство с именем content типа T.
Показать подсказку
Используйте интерфейс Box<T> {content: T; } Синтаксис.
Решение доступно после 3 попыток
Упражнение 3. Общее ограничение
Напишите универсальную функцию с именем getLength, которая принимает параметр arg. arg должен быть ограничен интерфейсом, имеющим свойство длины (число). Функция должна возвращать arg.length.
Показать подсказку
Объявите функцию как getLength<T расширяет HasLength>(arg: T): число и верните arg.length.
Решение доступно после 3 попыток
Упражнение 4: Общая пара
Определите универсальный интерфейс Pair<T, U> с двумя свойствами: первое — типа T, второе — типа U. Затем создайте универсальную функцию makePair, которая принимает первое (типа T) и второе (типа U) и возвращает объект, реализующий Pair<T, U>.
Показать подсказку
Используйте синтаксис для двух общих параметров Pair<T, U> и определите makePair соответствующим образом.
Решение доступно после 3 попыток