Дженерики в TypeScript: разбираемся вместе
Всем привет! Команда TestMace публикует очередной перевод статьи из мира web-разработки. На этот раз для новичков! Приятного чтения.
Развеем пелену таинственности и недопонимания над синтаксисом и наконец подружимся с ним
Наверное, только матёрые разработчики Java или других строго типизированных языков не хлопают глазами, увидев дженерик в TypeScript. Его синтаксис коренным образом отличается от всего того, что мы привыкли видеть в JavaScript, поэтому так непросто сходу догадаться, что он вообще делает.
Я бы хотел показать вам, что на самом деле всё гораздо проще, чем кажется. Я докажу, что если вы способны реализовать на JavaScript функцию с аргументами, то вы сможете использовать дженерики без лишних усилий. Поехали!
Дженерики в TypeScript
В документации TypeScript приводится следующее определение: «дженерики — это возможность создавать компоненты, работающие не только с одним, а с несколькими типами данных».
Здорово! Значит, основная идея состоит в том, что дженерики позволяют нам создавать некие повторно используемые компоненты, работающие с различными типами передаваемых им данных. Но как это возможно? Вот что я думаю.
Дженерики и типы соотносятся друг с другом, как значения и аргументы функции. Это такой способ сообщить компонентам (функциям, классам или интерфейсам), какой тип необходимо использовать при их вызове так же, как во время вызова мы сообщаем функции, какие значения использовать в качестве аргументов.
Лучше всего разобрать это на примере дженерика тождественной функции. Тождественная функция — это функция, возвращающая значение переданного в неё аргумента. В JavaScript она будет выглядеть следующим образом:
Сделаем так, чтобы она работала с числами:
Отлично, мы добавили в определение тождественной функции тип, но хотелось бы, чтобы она была более гибкой и срабатывала для значений любого типа, а не только для чисел. Именно для этого и нужны дженерики. Они позволяют функции принимать значения любого типа данных на входе и, в зависимости от них, преобразовывать саму функцию.
Посмотрите на вызов функции. Теперь-то синтаксис дженериков не должен вас пугать. T и U — это просто имена переменных, которые вы назначаете сами. При вызове функции вместо них указываются типы, с которыми будет работать данная функция.
Альтернативная версия понимания концепции дженериков состоит в том, что они преобразуют функцию в зависимости от указанного типа данных. На анимации ниже показано, как меняется запись функции и возвращаемый результат при изменении типа.
Как можно видеть, функция принимает любой тип, что позволяет создавать повторно используемые компоненты различных типов, как и было обещано в документации.
Обратите особое внимание на второй вызов console.log на анимации выше — в него не передаётся тип. В этом случае TypeScript попытается вычислить тип по переданным данным.
Обобщённые классы и интерфейсы
Вам уже известно, что дженерики — это всего лишь способ передать типы в компонент. Только что вы видели, как они работают с функциями, и у меня хорошие новости: с классами и интерфейсами они работают точно таким же образом. В этом случае указание типов следует после имени интерфейса или класса.
Посмотрите на пример и попробуйте разобраться сами. Надеюсь, у вас получилось.
Если код сразу не понятен, попробуйте отследить значения type сверху вниз вплоть до вызовов функции. Порядок действий следующий:
Реальные случаи использования: выходим за рамки примитивных типов
Результатом выполнения данного кода будет:
Подведем итоги
Надеюсь, я помог вам разобраться с дженериками. Запомните, всё, что вам нужно сделать, — это всего лишь передать значение type в функцию 🙂
Если хотите ещё почитать про дженерики, я прикрепил далее пару ссылок.
TypeScript: Обобщённые типы (Generics)
Серия
В двух предыдущих статьях мы говорили о том, что из себя представляет TypeScript, зачем и когда он может вам понадобиться, а также о том, какие типы и структуры будут встречаться вам каждый день при написании кода на этом надмножестве языка JavaScript.
Также, мы вскользь задели тему обобщений, когда разговаривали о типе пересечения. Сегодня мы поговорим об обобщённых типах подробнее.
Первый взгляд на обобщения
Обобщённый тип (обобщение, дженерик) позволяет резервировать место для типа, который будет заменён на конкретный, переданный пользователем, при вызове функции или метода, а также при работе с классами.
Посмотрим на простейшую реализацию функции, описанной выше, если бы в TypeScript не было обобщённых типов и нам пришлось бы довольствоваться тем, что уже есть.
Всё как в описании: функция принимает аргумент любого типа и возвращает его же. Однако, это не совсем так. Внимательно присмотритесь к типам: в примере указано, что функция принимает аргумент какого-то типа и возвращает значение какого-то типа, но при этом они никак не связаны. Грубо говоря, сейчас мы можем передать аргумент типа number и получить значение типа string – это валидно, потому что any подразумевает под собой всё что угодно.
Сейчас функция представляет собой «чёрный ящик», в который с одной стороны что-то входит, а с другой стороны что-то выходит, возможно, похожее на то, что входило или нет – непонятно. Я бы сказал, что такую функцию можно называть «обезличивающей функцией» в контексте типов. При использовании any в качестве типа возвращаемого значения мы обезличиваем результат функции.
Теперь перепишем функцию так, чтобы каждый из нас знал, что тип переданного аргумента является и типом возвращаемого значения.
В мире C#, технически, можно утверждать, что identity – это открытый тип, а identity – замкнутый. При этом нужно понимать, что вы можете работать только с замкнутыми типами.
Попробуем вызвать эту функцию с аргументом типа number и поверхностно проследим за тем, как компилятор определяет, что вернёт функция.
Логический вывод обобщённых типов
Многих разработчиков смущает указание типа с помощью знаков «меньше» и «больше». Для упрощения создания, чтения и работы с кодом TypeScript имеет возможность логического вывода типов при вызове обобщённых типов. Это значит, что компилятор будет пытаться определить (логически вывести) тип, который автоматически будет использоваться при вызове обобщённого типа.
В отличие от C#, в TypeScript нет возможности написать две функции с одним именем, когда первая функция реализована для конкретного типа, а вторая – для обобщённого. Например, такое в TypeScript написать не получится:
Также стоит упомянуть, что компилятор выдаст ошибку, если он не сможет точно вывести тип для параметр-типа. Для того, чтобы разрешить сложившуюся ситуацию нужно явно указать типы.
Для чего существуют обобщённые типы
При написании кода вы всегда встаёте перед выбором, имеющим как минимум две ветви решения. Первый путь приводит вас к копированию существующего кода с нужным вам типом, что также приводит к «распуханию» кода и необходимости думать при рефакторинге. Второй путь – унификация, что подразумевает под собой параметрический полиморфизм, в основе которого лежит использование одного и того же кода, но с разными типами. Получается, что обобщённые типы нужны для написания кода, который можно многократно использовать вне зависимости от типов.
Безопасность типов
Когда обобщённый код (например, алгоритм) применяется с конкретным типом, компилятор гарантирует нам, что в алгоритме будут использоваться лишь те «объекты», что совместимы с этим типом данных. В случае, если попытаться передать не совместимый с кодом тип, то компилятор породит ошибку.
Более простой и понятный код
Поскольку компилятор защищает нас от передачи аргументов неправильных типов, это позволяет использовать меньше защитников типов, которые были рассмотрены в предыдущей статье. Однако, работает только в том случае, если ваш стек полностью построен на TypeScript и это не будет работать в том случае, если вы распространяете свой код в скомпилированном виде. В таком случае вы обязаны использовать защитники типов, если хотите оберегать своих пользователей от неправильного использования вашего кода.
Базовые ограничения обобщённых типов
Посмотрим на код ниже и попытаемся ответить на вопрос: что здесь может пойти не так?
Ограничения позволяют сузить перечень типов, которые можно будет передать в обобщённом аргументе, и расширяет возможности по работе с этими типами.
Пусть у нас есть три объекта, каждый из которых представлен своим интерфейсом, соответственно:
Теперь попробуем передать в нашу функцию объект из переменной a и b :
Уточнения с помощью обобщений
Все мы знаем, что типов и поколений покемонов так много, что без TypeScript-а и структур данных здесь разобраться не получится. Давайте напишем простейший интерфейс, описывающий покемонов: тип, вес, высота и сила атаки.
А теперь напишем функцию, которая умеет работать не только с интерфейсом покемонов, но и с другими интерфейсами, используя обобщения.
Врядли кто-то из нас будет писать функцию, которая просто возвращает значение свойств без каких-либо ещё действий и логики. Конструкция keyof – это гарант того, что вы пытаетесь передать в функцию только разрешённый объект и существующее имя свойства, при этом взамен вы получаете не только значение свойства, но и его тип.
Ошибок нет. Типов нет. Уверенности в том, что функция не просто работает, а работает правильно – нет. Именно для этого нужна статическая типизация – для того, чтобы быть уверенным в том, что ваша функция работает так, как вы и задумывали. Здесь лишь одна оговорочка: речь идёт только про возвращаемый тип, а не про поведение функции.
Обобщения и интерфейсы
Обобщения не обошли стороной и интерфейсы.
Но это скучно и понятно – давайте попробуем посмотреть на более сложный пример. Допустим, имеется интефейс, описывающий пользователя какого-нибудь простенького сервиса:
Однако не спешите писать такой тип в ваших проектах сами: тип Partial уже существует в TypeScript и не требует пользовательского определения.
Некоторые встроенные типы для обобщений
В функциональном программировании, да и в программировании вообще, часто встречается необходимость изъять из какого-либо объекта не значение одного свойства, а двух или нескольких. Например, это может быть «фильтр» данных. Напишем такой «фильтр», используя уже знакомые нам типы и структуры, в рамках всё тех же покемонов.
Код немного грязный, но я не смог придумать более элегантного решения с типами.
Основные типы для обобщений:
TypeScript имеет большое количество стандартных типов, которые могут использоваться в вашем коде с обобщениями. Полный список не описывается в документации, но вы можете почитать описание ES5. Также существует модуль typescript-collections, имплементирующий многие «стандартные» структуры данных на TypeScript.
Обобщения в классах
Здесь особо не о чем говорить, потому что всё то, что можно сделать с обобщениями в интерфейсах – можно сделать и в классах. Просто имейте в виду. Зато здесь можно поговорить об ограничениях.
Ссылочки
По традиции оставляю пару ссылочек, которые помогут понять материал не только с моей стороны, но и со стороны других авторов. Не удивляйтесь, что в ссылках присутствуют материалы по C#, так как TypeScript берёт многие возможности именно из него – напомню, что у них один автор.
Делимся на оплату хостинга или кофе.
Чем чаще пью кофе, тем чаще пишу статьи.
Дженерики в TypeScript
Привет, я Сергей Вахрамов, занимаюсь фронтенд-разработкой на Angular в компании Тинькофф. Во фронтенд-разработку вошел напрямую с тайпскрипта, просто перечитав всю документацию. С того момента и спецификация ECMAScript расширилась, и TypeScript сильно подрос. Казалось бы, почему разработчики могут бояться дженериков, ведь бояться там нечего? Мой опыт общения с джуниор-разработчиками говорит, что во многом ребята не используют обобщенные типы просто потому, что кто-то пустил легенду об их сложности.
Эта статья для тех, кто не использует generic-типы в TypeScript: не знают о них, боятся использовать или используют вместо реальных типов — any .
Дженерики, или Generic Types, — обобщенные типы. Они нужны для описания похожих, но отличающихся какими-то характеристиками типов. Мы описываем общую структуру, а конкретную уже определяет пользователь дженерика. Дженерик — это каркас, внутренности которого заполняет разработчик. Программист, который описывает обобщенный тип, никогда не знает, что именно туда решит записать тот, кто будет этот тип использовать.
Посмотрим на пример использования дженериков в TypeScript. Представьте, что у нас есть массив значков валют. В JavaScript мы бы просто написали:
В TypeScript с помощью дженериков можно написать:
Оператор keyof
Это оператор, который берет все ключи объекта и представляет в виде числового или строкового литерального объединения.
Давайте представим, что нам с сервера шлют объект с такой структурой:
Если нам потребуются ключи из типа Payment, тут и пригодится оператор keyof.
Что дальше?
Мы дали основные знания, которые помогут уверенно использовать мощь обобщенных типов. Теперь можно переходить к Generic Types.
Случается, что в работе мы используем уже написанное до нас и не влияем на доработку кода.
Представим, что нам с сервера приходит описание платежа из истории в формате:
Потом кто-то разработал новый сервис, который отдает информацию о переводах. И он стал передавать информацию в следующем виде:
Теперь нам приходит код валюты, а не ее буквенное обозначение. При этом на старые записи в истории мы все еще получаем строковый код. Чтобы не описывать разные типы и не создавать путаницу, можно объединить их в один обобщенный тип — дженерик:
Можно указать типы параметров дженерика по умолчанию. Если не передать в такой дженерик параметр, то TypeScript возьмёт значение по умолчанию:
Возможно, пример не самый удачный, но он сделан для ввода в курс дела, дальше ждут более приближенные к реальной жизни примеры.
Интерфейсы тоже могут быть обобщёнными:
Типы и интерфейсы во многом похожи, но есть и различия — они подробно описаны в документации.
Типизация функций и методов
Некоторые из функций могут быть вызваны с разным количеством аргументов и их типами. В TypeScript такие функции можно описать с помощью перегрузок.
Допустим, у нас есть функция identity — она возвращает аргумент, который мы ей передали.
Но можно написать вот так:
В этом примере мы просто типизировали функцию (Function Declaration) через дженерик. Можно также типизировать функциональное выражение (Function Expression):
Типизация классов
Зачем может понадобиться обобщать классы? Уже на этапе разработки мы часто знаем, что один и тот же класс можно использовать для обслуживания разных данных. Например, выпадающему списку можно дать массив строк для отображения простого контента, а можно передать массив шаблонов для отрисовки сложного. Дженерики помогут описать такой класс.
Тот же самый класс будет выглядеть намного понятнее с TypeScript. Для начала опишем интерфейс:
Теперь напишем класс, который реализует наш интерфейс:
Ограничения дженериков. Generic Constraints
Иногда нужно как-то ограничить тип, принимаемый дженериком. Покажу на реальном примере.
Допустим, у нас есть функция для получения значения свойства length аргумента:
Если вы попробуете ее скомпилировать, получите ошибку:
Ошибка пропадет, а пример заработает. При этом разработчик, использующий функцию, будет точно понимать, какой аргумент требуется в нее передать.
Какой еще может быть практический пример? Давайте напишем функцию, которая принимает в себя объект и ключ, а выдает значение из переданного объекта по ключу:
В этом примере также показана возможность ограничения типа, используемого в объявлении функции, с помощью уже имеющегося параметра:
Охранники типов: Type Guards
Оператор typeof (typeof type guards). TypeScript — классный инструмент. Он позволяет выводить типы из конкретных переменных. Это называется Type Inference или «вывод типов».
Допустим, у нас уже есть переменная со ссылкой на объект, в котором записаны данные:
Если мы захотим вывести тип этой переменной в коде, то без проблем сделаем это при помощи typeof :
Почему typeof null === ‘object’? Это общепризнанное поведение JS. Многие считают его багом, попытаюсь объяснить почему.
Любая переменная хранит свое значение в виде последовательности битов. Из 32 бит, отведенных для хранения значения переменной, решили 3 выделить под хранение ее типа.
Оператор instanceof (instanceof type guards). Позволяет проверить, является ли данный объект экземпляром конкретного класса.
Тут ничего сложного. Для упрощения напишем классы без реализации и создадим экземпляры этих классов.
User-Defined Type Guards
В TypeScript есть еще один прекрасный инструмент — «определенные пользователем тайп-гарды».
Допустим, у нас есть следующие интерфейсы:
Мы можем легко это исправить. Достаточно лишь сказать TypeScript, что наша функция определяет, реализует ли переданный аргумент интерфейс Dog :
Теперь TypeScript не ругается, он понял тип переменной pet :
Сначала это может сложно восприниматься, поэтому подробнее про сужение типов предлагаю прочитать отдельно в документации.
Также хочу отметить, что при использовании Type Guard вся ответственность за определение типов лежит на разработчике. Он напрямую говорит TypeScript: «Это точно вот этот тип и никакой другой, я гарантирую».
В заключение
Мы узнали про дженерики и их параметризацию, научились с помощью них типизировать переменные, функции и методы, а также классы. Узнали, как можно ограничить типы и при необходимости помочь TypeScript с выведением типов, использовав Type Guard.
Если вы только начинаете использовать TypeScript в своей работе, начните с чтения официальной документации. Ее стоит изучить в первую очередь, просто сев и почитав несколько часов или, возможно, дней. Тогда сложится полное представление о языке. Вряд ли запомнится все и сразу, но уже будете знать, где что искать.
Для продвинутых пользователей языка рекомендую официальную книгу — TypeScript Handbook. Ее можно использовать как шпаргалку с паттернами, объяснением поведения системы вывода типов, описанием работы компилятора. Там раскрываются тонкие моменты, о которых разработчик не задумывается повседневно.
Если вы «познали дзен» в написании дженериков или просто хотите попрактиковаться на реальных примерах и набить руку, можете также порешать задачки Type Challenges в одноименном github-репозитории. В папке questions задачи разделены по сложности и пронумерованы. Под каждой есть ссылка на предлагаемые разработчиками решения — можете легко проверить себя.
Школа магии TypeScript: дженерики и расширение типов
Автор статьи, перевод которой мы сегодня публикуем, говорит, что TypeScript — это просто потрясающе. Когда он только начал пользоваться TS, ему страшно нравилась та свобода, которая присуща этому языку. Чем больше сил программист вкладывает в свою работу со специфичными для TS механизмами — тем значительнее получаемые им выгоды. Тогда он использовал аннотации типов лишь периодически. Иногда он пользовался возможностями по автодополнению кода и подсказками компилятора, но, в основном, полагался лишь на собственное видение решаемых им задач.
В итоге он пришёл к выводу о том, что лучше так не делать. Он подружился с компилятором, начал обращать внимание на его подсказки. Компилятор находит проблемы в коде и сообщает о них задолго до того, как они могут нанести реальный вред. Автор статьи, глядя на себя как на разработчика, понял, что компилятор — это его лучший друг, так как защищает его от него самого. Как тут не вспомнить слова Альбуса Дамблдора: «Требуется большая храбрость, чтобы выступить против своих врагов, но не меньше ее требуется и чтобы выступить против своих друзей».
Каким бы хорошим другом ни был компилятор, ему не всегда легко угодить. Иногда избежать использования типа any очень непросто. А порой кажется, что any — это единственное разумное решение некоей проблемы.
Этот материал посвящён двум ситуациям. Избежав использования в них типа any можно обеспечить типобезопасность кода, открыть возможности по его повторному использованию и сделать его интуитивно понятным.
Дженерики
Как видно, у нас имеется хорошая функция, но в ней не используются аннотации типов, а их отсутствие означает и то, что такую функцию нельзя назвать типобезопасной. Исправим это.
Так наша функция выглядит уже гораздо лучше. Компилятор теперь знает тип ожидаемого от неё результата, это пригодится нам позже. Однако для того, чтобы добиться безопасной работы с типами, мы пожертвовали возможностями повторного использования функции. Что если нам когда-нибудь понадобится применять её для получения каких-то других сущностей? Не может быть, чтобы эту функцию нельзя было бы уже никак улучшить. И это действительно так.
В TypeScript, как и в других языках со строгой типизацией, мы можем использовать дженерики (generics), которые ещё называют «обобщёнными типами», «универсальными типами», «обобщениями».
Использование дженериков и ключевого слова keyof — это весьма мощный приём. Если вы пишете программы в IDE, которая поддерживает TypeScript, то, вводя аргументы, вы сможете воспользоваться возможностями автодополнения, что очень удобно.
Надеюсь, что сейчас у вас сформировалось абсолютно чёткое понимание того, как пользоваться дженериками в TypeScript, но если вы, чтобы совсем хорошо всё усвоить, хотите поэкспериментировать с рассмотренным здесь кодом, можете заглянуть сюда.
Расширение существующих типов
Итак, этот код работает:
Если вы собираетесь расширить интерфейс внешней библиотеки, то вам, скорее всего, понадобится доступ к пространству имён ( namespace ) этой библиотеки. Вот пример того, как добавить поле userId к Request из библиотеки Express :
Поэкспериментировать с кодом из этого раздела можно здесь.
Итоги
В этом материале мы рассмотрели методики использования дженериков и расширения типов в TypeScript. Надеемся то, что вы сегодня узнали, поможет вам в написании надёжного, понятного и типобезопасного кода.
Уважаемые читатели! Как вы относитесь к типу any в TypeScript?
Обобщения (Generics) в TypeScript
Sep 25, 2017 · 5 min read
Введение
Одной из важнейших сторон при разработке программного обеспечения является создание компонентов с хорошо продуманной структурой и API. Но не менее важной частью является и возможность повторного использования этих компонентов. Компоненты, умеющие работать с разными наборами данных, предоставляют разработчикам дополнительные возможности при проектировании больших и сложных систем.
В таких языках, как Java или C#, одним из основных способов создания повторно используемых компонентов является использование обобщений (generics). Обобщения позволяют компоненту работать с различными типами данных в зависимости от потребностей разработчиков.
Самый простой пример с обобщениями в TypeScript
Для начала напишем фун к цию “идентичности” (это такая функция, которая возвращает то, что ей было передано в качестве параметра). Без использования обобщений, мы должны определить тип, который принимают аргументы функции и тип возвращаемого значения:
Конечно, в TypeScript мы можем указать any чтобы функцию можно было использовать для любого типа данных:
При использовании обобщений, мы можем явно указать тип аргумента и тем самым, в рамках нашего примера, определить тип возвращаемого значения. Для этого нам нужно воспользоваться специальной переменной типа, которая работает только с типами данных, а не их значениями:
Мы добавили переменную типа T к нашей функции. Эта переменная позволяет нам указывать конкретный тип при использовании функции. Помимо этого, мы указали и тип возвращаемого значения. И теперь мы знаем, что функция будет возвращать результат с тем же типом данных, что и у переданного аргумента.
Теперь посмотрим, как можно использовать нашу функцию. Есть два способа это сделать. Рассмотрим первый:
При вызове функции в угловых скобках мы явно указали тип данных, с которым будет работать функция.
Второй способ, — не указывать тип данных в угловых скобках, а просто передать переменную в качестве аргумента в функцию. В этом случае TypeScript задействует механизм, который называется автоматическим выводов типа, согласно значению, переданному в качестве аргумента.
Второй способ, с одной стороны, делает код короче, его легче читать, но, с другой стороны, это может привести к ошибкам. Ведь в этом случае можно передать в функцию значение, которого там не ожидается, и это может привести к ошибке во время выполнения.
Работа с обобщенными переменными типа
Снова рассмотрим функцию из предыдущего раздела:
Что, если мы в качестве аргумента передали массив и теперь хотим вывести в консоль его длину?:
Функцию, описанную выше, мы также можем переписать с использованием обобщенного типа данных Array языка TypeScript:
Обобщенные типы
В этом разделе мы рассмотрим, как создавать обобщенные типы функций и обобщенные интерфейсы.
Определение обобщенного типа функции очень похоже на определение типа для обычной функции. Отличием является лишь то, что нужно сначала указать тип передаваемых параметров и возвращаемого значения, как и при создании обобщенной функции:
Стоит отметить, что символ T при создании обобщений можно заменить на любой другой, если это необходимо. Иногда это помогает сделать код более понятным.
В данном примере использование U вместо T не очень правильно с точки зрения принятых стандартов программирования. Правильно называть обобщенный тип так, чтобы он всегда начинался с символа T (что означает тип — Type).
Тип обобщенной функции также можно записать с использованием объектного литерала:
По сути, это и есть обобщенный интерфейс. Давайте возьмем этот литерал и превратим в интерфейс:
Более того, мы можем указать обобщенный тип для всего интерфейса, что сделает этот параметр доступным для всех его методов. После этого мы сможем использовать обобщенную версию интерфейса, указывая конкретный тип данных (например, Dictionary вместо Dictionary ):
Обобщенные классы
Обобщенные классы описываются примерно также, как и обобщенные интерфейсы. Рассмотрим простой пример такого класса:
Поскольку это обобщенный класс, никто не запрещает нам вместо number использовать любой другой тип, например, string :
Как и в обобщенном интерфейсе, объявление параметра типа в названии класса говорит нам о том, что все свойства класса будут работать с данным типом данных.
В статье о классах языка TypeScript говорилось, что класс условно можно подразделить на две части: статическую и сам экземпляр. Так вот обобщения относятся только к части экземпляра класса. Статические же свойства не могут использовать параметр типа, указываемый в названии класса.
Ограничения обобщений
Давайте вспомним пример, рассмотренный выше в этой статье:
А что если есть еще такой тип данный, у которого есть такое же свойство и он не является массивом? Для решения этой проблемы TypeScript позволяет нам накладывать ограничения на обобщенные типы, т.е. мы можем указать для переменной типа базовый класс или интерфейс. Это будет означать, что в данную функцию можно будет передавать только удовлетворяющие установленным ограничениям типы данных.
Использование параметров типа в ограничениях
Можно определить параметр типа, который будет ограничен типом другого параметра типа. Например, мы хотим получить свойство объекта по его имени. И нам очень не хотелось бы, чтобы мы пытались получить свойство, которого на самом деле не существует. Для этого нужно ввести ограничение на второй параметр типа. Например:
Использование типов классов в обобщениях
При создании фабрик объектов в TypeScript с использованием обобщений, необходимо ссылаться на типы классов в функциях-конструкторах. Например:
В следующем примере показано как накладывать ограничения на типы создаваемых с помощью фабрики классов:
Примечание
В русскоязычной литературе по языкам программирования, в которых есть обобщения (например, C#), Generics чаще всего переводят как раз как “ обобщения”. И, как правило, так учат в ВУЗах. Лично мне ближе использование слова “ дженерики” вместо “ обобщения”. На мой взгляд это более понятно и правильно.





