В языке со статической типизацией, таком как TypeScript, обобщения — это способ улучшить возможность повторного использования кода за счет введения контролируемой степени смягчения типов. В этой короткой статье давайте подробно рассмотрим дженерики в Typescript и то, как мы можем использовать их для написания меньшего кода и улучшения общей ремонтопригодности наших проектов.
Дженерики:
Простой способ думать о дженериках — обращаться с ними как с заполнителями для типов.
Например, давайте предположим функцию, которая используется для добавления отзывов к объекту на нашей выдуманной платформе электронной коммерции. Этот объект может быть продуктом, продавцом или экземпляром доставки.
Конечно, мы могли бы иметь отдельные функции для добавления оценок к каждому типу объектов и иметь сильно дублированную и избыточную кодовую базу с копированием/вставкой, выполняемой слева и справа; или мы могли бы решить иметь чистую кодовую базу, используя дженерики следующим образом:
В приведенном выше примере T
является универсальным, и мы наложили на него ограничение, чтобы он принимал только RatableEntity
типов, которые могут быть продуктом, продавцом, экземпляром доставки, ответственным за доставку и т. д. без ограничения T
так же хорошо, как any
.
RatableEntity
может быть следующим интерфейсом:
Функция addRating
, которую мы создали выше, называется generic function
.
Общие интерфейсы и классы:
В TypeScript также можно создавать универсальные классы и универсальные интерфейсы. На самом деле интерфейс Array
— это built-in generic interface
в TypeScript.
Вот почему мы можем сделать что-то вроде следующего с массивами:
let numericArray = new Array<number>(); let stringArray = new Array<string>(); let myCustomObjectArray = new Array<MyCustomType>();
Приведенный выше код возможен, потому что Array<T>
— это определение интерфейса, которое представляет собой generic interface
.
Общий интерфейс:
Давайте напишем наш собственный общий интерфейс в этом разделе, чтобы лучше понять эту идею:
Представьте, что нашему приложению необходимо вести учет сотрудников и их руководителей. Давайте сначала создадим интерфейс Employee следующим образом:
Department
— это настраиваемый пользовательский тип, который определяется следующим образом:
type Department = "HR" | "Engineering" | "Sales" | "Finance"
Поскольку менеджер также является сотрудником, все вышеперечисленные поля в интерфейсе Employee
применимы и к менеджеру. Предположим, в данных менеджера будет дополнительное поле о количестве людей, которыми он управляет. Мы можем преобразовать интерфейс Employee в общий, чтобы учесть это и различать, является ли Employee менеджером или нет, следующим образом:
Теперь мы можем использовать общий интерфейс Employee следующим образом:
Общий класс:
В TypeScript также можно создавать общие классы. Давайте рассмотрим практический пример, чтобы понять, как мы можем создавать экземпляры с помощью универсального класса.
Давайте создадим общий classQueue<T>
, который будет нашей собственной реализацией очереди в Typescript, следующим образом:
Теперь мы могли бы использовать приведенный выше универсальный класс для создания различных экземпляров очередей однородных типов данных следующим образом:
let numericQueue = new Queue<number>(); let stringQueue = new Queue<string>();
Таким образом, мы можем повторно использовать один и тот же класс Queue для создания разных типов очередей с разными типами данных.
Практически мы избавились от написания лишнего кода с помощью дженериков.
Вывод:
Таким образом, в этой статье мы рассмотрели некоторые расширенные варианты использования дженериков TypeScript, таких как generics with constraints
, generic functions
, generic interfaces
и generic classes
.
Спасибо за чтение этой статьи, и если вы нашли этот контент полезным и хотели бы поддержать меня в создании большего количества подобного контента, не стесняйтесь нажимать кнопку ниже, которая приведет вас на мою страницу ko-fi.