Дженерики
Основная цель разработки дженериков состоит в том, чтобы обеспечить значимые ограничения между членами, которые могут быть:
Экземпляр класса
Методы класса
Функциональный параметр
Возвращаемое значение функции
Мотивация и примеры
Вот простая реализация структуры данных «первым пришел - первым вышел», очереди в TypeScript и JavaScript.
class Queue {
private data = [];
push = item => this.data.push(item);
pop = () => this.data.shift();
}В приведенном выше коде есть проблема: он позволяет добавлять в очередь данные любого типа, конечно, когда данные выталкиваются из очереди, они также могут быть любого типа. В приведенном ниже примере кажется, что можно добавить данные типа string в очередь, но на практике это использование предполагает, что в очередь будет добавлен только тип number.
class Queue {
private data = [];
push = item => this.data.push(item);
pop = () => this.data.shift();
}
const queue = new Queue();
queue.push(0);
queue.push('1'); // Oops,ошибка
// Пользователь, в недоразумении
console.log(queue.pop().toPrecision(1));
console.log(queue.pop().toPrecision(1)); // RUNTIME ERRORОдно из решений (на самом деле это единственное решение, которое не поддерживает универсальные типы) - это создание специальных классов для этих ограничений, таких как быстрое создание очереди числовых типов:
Конечно, скорость также означает боль. Например, если вы хотите создать очередь из строк, вам придется снова немного изменить код. Один из способов, которым мы действительно хотим, заключается в том, что независимо от того, какой тип помещается в очередь, выдвигаемый тип совпадает с выдвигаемым типом. Это легко, когда вы используете дженерики:
Другой пример, который мы видели: reverse функция, которая теперь предоставляет ограничения на параметры функции и возвращаемые значения:
В этом разделе вы узнали примеры использования дженериков в классах и функциях. Стоит добавить, что вы можете добавить универсальные элементы к функциям-методам, которые вы создаете:
Неправильные дженерики
Я видел, как разработчики используют дженерики только для взлома. Когда вы используете его, вы должны спросить себя: какие ограничения вы хотите использовать для его предоставления. Если вы не можете ответить правильно, вы можете использовать дженерики, такие как:
Здесь нет необходимости использовать дженерики, поскольку они используются только для позиции одного параметра. Возможно, лучше использовать:
Дизайн шаблона: удобный и универсальный
Рассмотрим следующую функцию:
В этом случае универсальный T используется только в одном месте, он не обеспечивает ограничение T между членами. Это эквивалентно утверждению типа, как это:
Дженерики, которые используются только один раз, не более безопасны, чем утверждение типа. Оба они обеспечивают удобство использования API.
Другой очевидный пример - функция загрузки возвращаемого значения json, которая возвращает Promise любого из переданных вами типов:
Обратите внимание, что вам все еще нужно явно сообщить тип, который вам нужен, но подпись getJSON<T> в config => Promise<T> может сократить некоторые ваши ключевые шаги (вам не нужно сообщить возвращаемый тип loadUsers, потому что его можно вытолкнуть):
Также возвращаемое значение с использованием Promise<T> как функции намного лучше, чем некоторые альтернативы, такие как Promise<any>.
Использование с axios
При нормальных обстоятельствах мы будем помещать формат данных бэкэнда в интерфейс отдельно:
Когда мы разделяем API на один модуль:
Затем мы записываем возвращаемый тип данных User, который позволяет TypeScript выводить нужный нам тип:
Last updated
Was this helpful?