К концу этой статьи вы узнаете о дженериках машинописных текстов, о том, что они из себя представляют, о вариантах их использования и о нескольких примерах.
В некоторых случаях типы, которые мы создаем, можно повторно использовать как другие типы в другом контексте, и нам не нужно начинать дублирование для каждого варианта использования, мы можем использовать дженерик, чтобы избежать дублирования. Дженерики используются для создания повторно используемых типов, как параметры для функций, так и дженерики для типов.
Например,
enum Subject = { Maths = 'Maths', English = 'English', Deutsch = 'Deutsch' } type Book = { subject: Subject, author: string, year: number } /** this function is expected to receive math books only, both book can be Maths, Deutsch or English */ function takeMathsBookOnly(book: Book) { }
В приведенном выше фрагменте кода у нас есть тип Book
со свойством subject
enum Subject
, которое может быть Maths, English или Deutsch, а также функция takeMathsBookOnly
, которая ожидает получать только книги по математике. Однако книги, как мы знаем, могут быть любой тематики.
Мы можем написать защиту типа внутри функции или написать какое-то условие, чтобы определить, что тема книги — Математика, но всей этой сложной логики можно избежать, используя дженерики, мы можем создать определенный тип для каждый предмет с помощью дженериков.
enum Subject = { Maths = 'Maths', English = 'English', Deutsch = 'Deutsch' } // Default parameter = Subject, meaning Book type Book<T = Subject> = { subject: T, // subject: Subject author: string, year: number } type MathBook = Book<Subject.Maths> /** subject can only be equal to 'Maths' { subject: Subject.Maths, author: string, year: number } **/ type EnglishBook = Book<Subject.English> /** subject can only be equal to 'English' { subject: Subject.English, author: string, year: number } **/ type DeutschBook = Book<Subject.Deutsch> /** subject can only be equal to 'Deutsch' { subject: Subject.Deutsch, author: string, year: number } **/ function takeMathsBookOnly(book: MathBook) { }
Из приведенного выше фрагмента Book
теперь принимает переменную универсального типа с именем T
, T
точно так же, как параметры функции принимают Subject
в качестве типа по умолчанию, поэтому тип Book
такой же, как и предыдущая функциональность, однако дополнительное преимущество заключается в том, что теперь мы можем повторно использовать Book
в разных контекстах, мы можем создать MathBook
тип, только передав Subject.Maths
в качестве аргумента Book
, поэтому в случае T = Subject.Maths
. Мы можем создать столько конкретных типов, сколько захотим, используя дженерики.
Другой общий вариант использования
// generic map function const map = <T, U>(items: T[], fn: (item: T) => U): U[] => { const result: U[] = []; for (let item of items) { result.push(fn(item)); } return result; } const doubleNumbers = map<number, number>([1, 2, 3, 4, 5], (item) => item * 2); // [2, 4, 6, 8, 10] const stringifyDoubleNumbers = map<number, string>([1, 2, 3, 4, 5], (item) => `${item * 2}`); // ['2', '4', '6', '8', '10']
Давайте рассмотрим еще один общий вариант использования, в приведенном выше фрагменте у нас есть общая функция map
с двумя переменными общего типа T
и U
, которая принимает items
, являющуюся массивом T
, и функция обратного вызова fn
, которая принимает элемент типа T
и возвращает U
, иногда U
может быть таким же, как T
как в doubleNumbers
, но это не всегда так, нам может понадобиться преобразовать элементы в другой тип, как в stringifyDoubleNumbers
который получает массив number
, но возвращает массив string
.
Чтобы узнать больше о дженериках, ознакомьтесь с разделом Typescript Generics. Спасибо