Дженерики (универсальные типы) в TypeScript

Источник: «Generics In TypeScript»
Дженерики играют решающую роль в программировании, поскольку они позволяют создавать типобезопасные функции без предварительного указания точного типа, но допуская ограничения и проверки типов программистом. В этой статье представлена концепция дженериков, перечислены их преимущества и показано, как их использовать.

Дженерики в TypeScript позволяют разработчикам писать многоразовый и гибкий код, абстрагируясь от типов. Используя дженерики, разработчики могут создавать функции, классы и интерфейсы, которые работают с любым типом, а не ограничиваются определённым типом. Возможность создавать компонент, который может работать с несколькими типами, а не только с одним, является одним из основных инструментов в наборе инструментов для создания повторно используемых элементов в таких языках программирования, как C# и Java. В результате пользователи могут использовать разные типы при использовании этих компонентов.

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

Преимущества Дженериков

Список преимуществ, которые предлагают дженерики в TypeScript, выглядит следующим образом:

Использование дженериков в функциях

Используя дженерики в функциях, вы можете создавать код, которым может обрабатывать различные типы данных. А также делает ваш код более гибким и пригодным для повторного использования, поскольку его можно применять к разным типам ввода, не требуя отдельных функций для каждого типа. В результате ваш код становиться легче поддерживать и понимать. Разработчики определяют тип заполнителя в угловых скобках, например <T>, и используют этот тип заполнителя внутри функции для реализации дженериков.

Ниже приведён пример того, как написать функцию, которая возвращает первый элемент массива array. Вот пример функции возвращающей первый элемент массива в TypeScript с использованием дженериков:

function firstelement<T>(arr: T[]): T {
return arr[0];
}

Чтобы использовать функцию с различными типами массивов, при вызове функции передаётся определённый тип. Например:

function firstElement<T>(array: T[]): T | undefined {
return array[0];
}

const numbers = [1, 2, 3];
const firstNumber = firstElement<number>(numbers);
console.log(firstNumber); // 1

const names = ["Daniel", "Micheal", "Charlie"];
const firstName = firstElement<string>(names);
console.log(firstName); // 'Daniel'

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

Использование дженериков в классах и интерфейсах

Дженерики также можно использовать в классах и интерфейсах. Например, класс представляющий стек, может быть написан с типом дженерик для поддержки любого типа данных.

class Stack<T> {
private data: T[] = [];
push(item: T) {
this.data.push(item);
}
pop(): T | undefined {
return this.data.pop();
}
}

let numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
console.log(numberStack.pop()); // 2
console.log(numberStack.pop()); // 1

let stringStack = new Stack<string>();
stringStack.push("a");
stringStack.push("b");
console.log(stringStack.pop()); // 'b'
console.log(stringStack.pop()); // 'a'

Чтобы использовать класс с разными типами данных, конкретный тип передаётся при создании экземпляра класса. Например:

let numbers = new Stack<number>();
numbers.push(1);
numbers.push(2);
console.log(numbers.pop()); // 2
console.log(numbers.pop()); // 1

let names = new Stack<string>();
names.push("Alice");
names.push("Bob");
console.log(names.pop()); // 'Bob'
console.log(names.pop()); // 'Alice'

В этом примере класс используется для создания двух стеков разных типов: numbers (стек чисел) и names (стек строк). Класс может работать с соответствующим типом данных, передавая определённый тип при создании экземпляра класса.

Встроенный дженерик (универсальный тип) и интерфейсы

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

let numbers = [1, 2, 3];
let names = ['Daniel', 'Micheal', 'Charlie'];

Другим примером является тип Promise, представляющий значений, которое может быть ещё недоступно, но будет доступно в какой-то момент в будущем. Тип Promise также определяется с помощью дженерика (универсального типа), представляющего значение, которое будет доступно в будущем.

let promise: Promise<string> = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hello, World!");
}, 1000);
});

promise.then((value: string) => console.log(value)); // 'Hello, World!'

Наконец, Map — это дженерик (универсальный тип), представляющий набор пар ключ-значение. Дженерики (универсальные типы) для ключей и значений могут быть разными.

let map = new Map<string, number>();
map.set("Daniel", 25);
map.set("Michael", 30);
console.log(map.get("Daniel")); // 25

Помимо использования этих встроенных дженериков (универсальных типов) и интерфейсов, вы также можете расширить их для добавления дополнительных функций. Например, вы можете создать собственный класс Stack, расширяющий встроенный тип Array, как показано в предыдущем примере. Это позволяет использовать преимущества встроенной функциональности типа Array при добавлении пользовательских функций.

Заключение

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

Дополнительные материалы

Предыдущая Статья

Три причины изучить Laravel

Следующая Статья

Sass для веб-разработки