Обобщённые типы
Можно объявлять и свои обобщённые типы. Магазин продаёт коробки. У каждой коробки есть надпись, а внутри лежит разное: монеты, стрелы, меч. Вместо отдельного типа для каждой коробки объявим один тип с параметром типа:
type Box<T> = { label: string; content: T };Параметр типа пишут в угловых скобках после имени типа, а внутри типа T используют как любой другой тип. Тогда Box<number> — это { label: string; content: number }, а Box<string[]> — коробка с массивом строк. TypeScript проверяет содержимое по аргументу типа:
type Box<T> = { label: string; content: T };
const coins: Box<number> = { label: "Монеты", content: 50 };
const arrows: Box<string[]> = { label: "Стрелы", content: ["Огненная стрела", "Ледяная стрела"] };
const sword: Box<number> = { label: "Меч", content: "Серебряный меч" };TypeScript сообщает:
main.ts(5,44): error TS2322: Type 'string' is not assignable to type 'number'.Коробка sword объявлена как коробка с числом. Для переменной аргумент типа нужно писать всегда; без него const sword: Box = … даст Generic type 'Box' requires 1 type argument(s). (TS2314), как и с Array.
У интерфейсов тоже бывают параметры типа, а у типа их может быть несколько:
interface Shelf<T> {
name: string;
items: T[];
}
type Pair<A, B> = [A, B];
const potionShelf: Shelf<string> = { name: "Зелья", items: ["Лечебное зелье", "Эликсир"] };
const priceTag: Pair<string, number> = ["Серебряный меч", 120];Обобщённые типы в обобщённых функциях. Функция, которая принимает любую коробку, тоже обобщённая:
type Box<T> = { label: string; content: T };
function unpack<T>(box: Box<T>): T {
console.log(`Распаковываем: ${box.label}`);
return box.content;
}
const coins: Box<number> = { label: "Монеты", content: 50 };
const gold = unpack(coins) + 20;
console.log(gold);Программа выводит:
Распаковываем: Монеты
70В unpack(coins) TypeScript видит, что coins — это Box<number>, поэтому T — это number, и unpack возвращает число: прибавить к нему 20 можно. Для Box<string[]> она вернула бы string[].
Задание
- 1
Объявите обобщённый тип
Chest<T>для сундука с местомlocation(строка) и добычейlootтипаT. Затем создайте два сундука:goldChestтипаChest<number>в месте"Пещера гоблинов"с добычей120иpotionChestтипаChest<string[]>в месте"Башня волшебника"с добычей["Лечебное зелье", "Эликсир"]. - 2
Напишите обобщённую функцию
openChest<T>(chest: Chest<T>): T. Она выводитОткрываем сундук:и место, где лежит сундук, напримерОткрываем сундук: Пещера гоблинов, и возвращает добычу сундука. - 3
Кира открывает оба сундука. Добавьте в конец программы такие строки:
gold = gold + openChest(goldChest); for (const potion of openChest(potionChest)) { inventory.push(potion); } console.log(`Золото: ${gold}`); console.log(inventory);Программа выведет:
Открываем сундук: Пещера гоблинов Открываем сундук: Башня волшебника Золото: 170 ["Лук", "Лечебное зелье", "Эликсир"]TypeScript знает, что первый вызов возвращает число, которое можно прибавить к
gold, а второй —string[], элементы которого подходят дляinventory.