Дженерики (универсальные типы) в TypeScript
Дженерики в TypeScript позволяют разработчикам писать многоразовый и гибкий код, абстрагируясь от типов. Используя дженерики, разработчики могут создавать функции, классы и интерфейсы, которые работают с любым типом, а не ограничиваются определённым типом. Возможность создавать компонент, который может работать с несколькими типами, а не только с одним, является одним из основных инструментов в наборе инструментов для создания повторно используемых элементов в таких языках программирования, как C# и Java. В результате пользователи могут использовать разные типы при использовании этих компонентов.
В этой статье представлена идея Дженериков в TypeScript и когда их использовать. В ней описывается, как можно использовать дженерики с функциями, классами, интерфейсами и типами, и приводятся примеры их использования в реальных ситуациях. Эти примеры чётко определены, поэтому вы можете следовать им в предпочитаемой вами интегрированной среде разработки.
Преимущества Дженериков
Список преимуществ, которые предлагают дженерики в 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 делает код более читабельным и удобным для сопровождения, а также уменьшает количество дублированного кода.