Что такое дженерики typescript

ТипScript для начинающих, часть 5: Generics

Russian (Pусский) translation by Ilya Nikov (you can also view the original English article)

Второй учебник в нашей серии TypeScript для начинающих посвящен основным типам данных, доступных в TypeScript. Проверка типов в TypeScript позволяет нам убедиться, что переменные в нашем коде могут иметь только определенные типы значений, назначенные им. Таким образом, мы можем избежать множества ошибок при написании кода, потому что IDE сможет рассказать нам, когда мы выполняем операцию над типом, который ее не поддерживает. Это делает проверку типов одной из лучших функций TypeScript.

Потребность в генериках

Если вы не знакомы с дженериками, вам может быть интересно, зачем они вообще нужны. В этом разделе я отвечу на этот вопрос. Начнем с написания функции, которая вернет случайный элемент из массива чисел.

Через некоторое время, скажем, вам нужно получить случайный строковый элемент из массива строк. На этом этапе вы можете решить создать другую функцию, специально предназначенную для строк.

Что делать, если вам нужно выбрать случайный элемент из массива интерфейса, который вы определили? Создание новой функции каждый раз, когда вы хотите получить случайный элемент из массива различных объектов, невозможно.

Как вы можете видеть, мы можем использовать указанную выше функцию для получения случайных позиций, а также случайных цветов. Одна из основных проблем с этим решением заключается в том, что вы потеряете информацию о возвращаемом типе возвращаемого значения.

Лучшим решением для избежания дублирования кода при сохранении информации о типе является использование дженериков. Вот общая функция, которая возвращает случайные элементы из массива.

Что такое дженерики typescript. Смотреть фото Что такое дженерики typescript. Смотреть картинку Что такое дженерики typescript. Картинка про Что такое дженерики typescript. Фото Что такое дженерики typescriptЧто такое дженерики typescript. Смотреть фото Что такое дженерики typescript. Смотреть картинку Что такое дженерики typescript. Картинка про Что такое дженерики typescript. Фото Что такое дженерики typescript Что такое дженерики typescript. Смотреть фото Что такое дженерики typescript. Смотреть картинку Что такое дженерики typescript. Картинка про Что такое дженерики typescript. Фото Что такое дженерики typescript

Использование дженериков может показаться очень ограниченным

Это связано с тем, что TypeScript не может делать никаких предположений о типе переменной, которая будет передана нашей общей функции заранее. В результате наша общая функция может использовать только те операции, которые применимы ко всем типам данных. Следующий пример должен сделать эту концепцию более понятной.

Вышеупомянутая функция удалит все вхождения указанного символа из заданной строки. Возможно, вам захочется создать общую версию этой функции, чтобы вы могли также удалить определенные цифры из заданного числа, а также символы из строки. Вот соответствующая общая функция.

Это ограничение на использование разных методов в общей функции может заставить вас думать, что концепция дженериков в конце концов не будет иметь большого смысла. Мало чего вы можете сделать с помощью нескольких методов, которые должны применяться ко всем типам данных, чтобы вы могли использовать их в общей функции.

Одна важная вещь, которую вы должны запомнить на этом этапе, заключается в том, что вам обычно не нужно создавать функции, которые будут использоваться со всеми типами данных. Чаще всего создается функция, которая будет использоваться с определенным набором или диапазоном типов данных. Это ограничение на типы данных делает общие функции более полезными.

Создание общих функций с использованием ограничений

Общая функция removeIt из предыдущего раздела обнаружила ошибку, поскольку метод replace внутри нее предназначен для использования со строками, тогда как переданные ему параметры могут иметь любой тип данных.

Вот общая функция, которая печатает имя людей, членов семьи или знаменитостей, переданных ей.

Заключение

В этом уроке я попытался осветить основы дженериков в TypeScript в удобной для новичков форме. Мы начали статью, обсуждая необходимость создания дженериков. После этого мы узнали о правильном способе использования дженериков, чтобы избежать дублирования кода, не жертвуя способностью проверки типов. Когда вы поймете основы, обсуждаемые здесь, вы можете прочитать больше о дженериках в официальной документации.

Если у вас есть какие-либо вопросы, связанные с этим руководством, я буду рад ответить на них в комментариях.

Источник

Дженерики в TypeScript: разбираемся вместе

Всем привет! Команда TestMace публикует очередной перевод статьи из мира web-разработки. На этот раз для новичков! Приятного чтения.

Развеем пелену таинственности и недопонимания над синтаксисом и наконец подружимся с ним

Что такое дженерики typescript. Смотреть фото Что такое дженерики typescript. Смотреть картинку Что такое дженерики typescript. Картинка про Что такое дженерики typescript. Фото Что такое дженерики typescript

Наверное, только матёрые разработчики Java или других строго типизированных языков не хлопают глазами, увидев дженерик в TypeScript. Его синтаксис коренным образом отличается от всего того, что мы привыкли видеть в JavaScript, поэтому так непросто сходу догадаться, что он вообще делает.

Я бы хотел показать вам, что на самом деле всё гораздо проще, чем кажется. Я докажу, что если вы способны реализовать на JavaScript функцию с аргументами, то вы сможете использовать дженерики без лишних усилий. Поехали!

Дженерики в TypeScript

В документации TypeScript приводится следующее определение: «дженерики — это возможность создавать компоненты, работающие не только с одним, а с несколькими типами данных».

Здорово! Значит, основная идея состоит в том, что дженерики позволяют нам создавать некие повторно используемые компоненты, работающие с различными типами передаваемых им данных. Но как это возможно? Вот что я думаю.

Дженерики и типы соотносятся друг с другом, как значения и аргументы функции. Это такой способ сообщить компонентам (функциям, классам или интерфейсам), какой тип необходимо использовать при их вызове так же, как во время вызова мы сообщаем функции, какие значения использовать в качестве аргументов.

Лучше всего разобрать это на примере дженерика тождественной функции. Тождественная функция — это функция, возвращающая значение переданного в неё аргумента. В JavaScript она будет выглядеть следующим образом:

Сделаем так, чтобы она работала с числами:

Отлично, мы добавили в определение тождественной функции тип, но хотелось бы, чтобы она была более гибкой и срабатывала для значений любого типа, а не только для чисел. Именно для этого и нужны дженерики. Они позволяют функции принимать значения любого типа данных на входе и, в зависимости от них, преобразовывать саму функцию.

Что такое дженерики typescript. Смотреть фото Что такое дженерики typescript. Смотреть картинку Что такое дженерики typescript. Картинка про Что такое дженерики typescript. Фото Что такое дженерики typescript

Что такое дженерики typescript. Смотреть фото Что такое дженерики typescript. Смотреть картинку Что такое дженерики typescript. Картинка про Что такое дженерики typescript. Фото Что такое дженерики typescript

Посмотрите на вызов функции. Теперь-то синтаксис дженериков не должен вас пугать. T и U — это просто имена переменных, которые вы назначаете сами. При вызове функции вместо них указываются типы, с которыми будет работать данная функция.

Альтернативная версия понимания концепции дженериков состоит в том, что они преобразуют функцию в зависимости от указанного типа данных. На анимации ниже показано, как меняется запись функции и возвращаемый результат при изменении типа.

Что такое дженерики typescript. Смотреть фото Что такое дженерики typescript. Смотреть картинку Что такое дженерики typescript. Картинка про Что такое дженерики typescript. Фото Что такое дженерики typescript

Как можно видеть, функция принимает любой тип, что позволяет создавать повторно используемые компоненты различных типов, как и было обещано в документации.

Обратите особое внимание на второй вызов console.log на анимации выше — в него не передаётся тип. В этом случае TypeScript попытается вычислить тип по переданным данным.

Обобщённые классы и интерфейсы

Вам уже известно, что дженерики — это всего лишь способ передать типы в компонент. Только что вы видели, как они работают с функциями, и у меня хорошие новости: с классами и интерфейсами они работают точно таким же образом. В этом случае указание типов следует после имени интерфейса или класса.

Посмотрите на пример и попробуйте разобраться сами. Надеюсь, у вас получилось.

Если код сразу не понятен, попробуйте отследить значения type сверху вниз вплоть до вызовов функции. Порядок действий следующий:

Реальные случаи использования: выходим за рамки примитивных типов

Результатом выполнения данного кода будет:

Подведем итоги

Надеюсь, я помог вам разобраться с дженериками. Запомните, всё, что вам нужно сделать, — это всего лишь передать значение type в функцию 🙂

Если хотите ещё почитать про дженерики, я прикрепил далее пару ссылок.

Источник

Школа магии TypeScript: дженерики и расширение типов

Автор статьи, перевод которой мы сегодня публикуем, говорит, что TypeScript — это просто потрясающе. Когда он только начал пользоваться TS, ему страшно нравилась та свобода, которая присуща этому языку. Чем больше сил программист вкладывает в свою работу со специфичными для TS механизмами — тем значительнее получаемые им выгоды. Тогда он использовал аннотации типов лишь периодически. Иногда он пользовался возможностями по автодополнению кода и подсказками компилятора, но, в основном, полагался лишь на собственное видение решаемых им задач.

Что такое дженерики typescript. Смотреть фото Что такое дженерики typescript. Смотреть картинку Что такое дженерики typescript. Картинка про Что такое дженерики typescript. Фото Что такое дженерики typescript

В итоге он пришёл к выводу о том, что лучше так не делать. Он подружился с компилятором, начал обращать внимание на его подсказки. Компилятор находит проблемы в коде и сообщает о них задолго до того, как они могут нанести реальный вред. Автор статьи, глядя на себя как на разработчика, понял, что компилятор — это его лучший друг, так как защищает его от него самого. Как тут не вспомнить слова Альбуса Дамблдора: «Требуется большая храбрость, чтобы выступить против своих врагов, но не меньше ее требуется и чтобы выступить против своих друзей».

Каким бы хорошим другом ни был компилятор, ему не всегда легко угодить. Иногда избежать использования типа any очень непросто. А порой кажется, что any — это единственное разумное решение некоей проблемы.

Этот материал посвящён двум ситуациям. Избежав использования в них типа any можно обеспечить типобезопасность кода, открыть возможности по его повторному использованию и сделать его интуитивно понятным.

Дженерики

Как видно, у нас имеется хорошая функция, но в ней не используются аннотации типов, а их отсутствие означает и то, что такую функцию нельзя назвать типобезопасной. Исправим это.

Так наша функция выглядит уже гораздо лучше. Компилятор теперь знает тип ожидаемого от неё результата, это пригодится нам позже. Однако для того, чтобы добиться безопасной работы с типами, мы пожертвовали возможностями повторного использования функции. Что если нам когда-нибудь понадобится применять её для получения каких-то других сущностей? Не может быть, чтобы эту функцию нельзя было бы уже никак улучшить. И это действительно так.

В TypeScript, как и в других языках со строгой типизацией, мы можем использовать дженерики (generics), которые ещё называют «обобщёнными типами», «универсальными типами», «обобщениями».

Использование дженериков и ключевого слова keyof — это весьма мощный приём. Если вы пишете программы в IDE, которая поддерживает TypeScript, то, вводя аргументы, вы сможете воспользоваться возможностями автодополнения, что очень удобно.

Надеюсь, что сейчас у вас сформировалось абсолютно чёткое понимание того, как пользоваться дженериками в TypeScript, но если вы, чтобы совсем хорошо всё усвоить, хотите поэкспериментировать с рассмотренным здесь кодом, можете заглянуть сюда.

Расширение существующих типов

Итак, этот код работает:

Если вы собираетесь расширить интерфейс внешней библиотеки, то вам, скорее всего, понадобится доступ к пространству имён ( namespace ) этой библиотеки. Вот пример того, как добавить поле userId к Request из библиотеки Express :

Поэкспериментировать с кодом из этого раздела можно здесь.

Итоги

В этом материале мы рассмотрели методики использования дженериков и расширения типов в TypeScript. Надеемся то, что вы сегодня узнали, поможет вам в написании надёжного, понятного и типобезопасного кода.

Уважаемые читатели! Как вы относитесь к типу any в TypeScript?

Источник

Дженерики в TypeScript

Привет, я Сергей Вахрамов, занимаюсь фронтенд-разработкой на Angular в компании Тинькофф. Во фронтенд-разработку вошел напрямую с тайпскрипта, просто перечитав всю документацию. С того момента и спецификация ECMAScript расширилась, и TypeScript сильно подрос. Казалось бы, почему разработчики могут бояться дженериков, ведь бояться там нечего? Мой опыт общения с джуниор-разработчиками говорит, что во многом ребята не используют обобщенные типы просто потому, что кто-то пустил легенду об их сложности.

Эта статья для тех, кто не использует generic-типы в TypeScript: не знают о них, боятся использовать или используют вместо реальных типов — any .

Что такое дженерики typescript. Смотреть фото Что такое дженерики typescript. Смотреть картинку Что такое дженерики typescript. Картинка про Что такое дженерики typescript. Фото Что такое дженерики typescript

Дженерики, или 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. Часть 6. Манипуляции с типами

Что такое дженерики typescript. Смотреть фото Что такое дженерики typescript. Смотреть картинку Что такое дженерики typescript. Картинка про Что такое дженерики typescript. Фото Что такое дженерики typescript

Мы продолжаем серию публикаций адаптированного и дополненного перевода «Карманной книги по TypeScript «.

Обратите внимание: для большого удобства в изучении книга была оформлена в виде прогрессивного веб-приложения.
Система типов TS позволяет создавать типы на основе других типов.

Простейшей формой таких типов являются дженерики или общие типы (generics). В нашем распоряжении также имеется целый набор операторов типа. Более того, мы можем выражать типы в терминах имеющихся у нас значений.

Дженерики

Для того, чтобы сделать эту функцию более универсальной, можно использовать тип any :

Однако, при таком подходе мы не будем знать тип возвращаемого функцией значения.

Нам нужен какой-то способ перехватывать тип аргумента для обозначения с его помощью типа возвращаемого значения. Для этого мы можем воспользоваться переменной типа, специальным видом переменных, которые работают с типами, а не со значениями:

Мы используем переменную Type как для типа передаваемого функции аргумента, так и для типа возвращаемого функцией значения.

Такие функции называют общими (дженериками), поскольку они могут работать с любыми типами.

Мы можем вызывать такие функции двумя способами. Первый способ заключается в передаче всех аргументов, включая аргумент типа:

В данном случае принимаемым и возвращаемым типами является строка.

Второй способ заключается в делегировании типизации компилятору:

Второй способ является более распространенным. Однако, в более сложных случаях может потребоваться явное указание типа, как в первом примере.

Работа с переменными типа в дженериках

Что если мы захотим выводить в консоль длину аргумента arg перед его возвращением?

Изменим сигнатуру функции таким образом, чтобы она работала с массивом Type :

Мы можем сделать тоже самое с помощью такого синтаксиса:

Общие типы

Тип общей функции (функции-дженерика) похож на тип обычной функции, в начале которого указывается тип параметра:

Мы можем использовать другое название для параметра общего типа:

Мы также можем создавать общие типы в виде сигнатуры вызова типа объектного литерала:

Это приводит нас к общему интерфейсу:

Для того, чтобы сделать общий параметр видимым для всех членов интерфейса, его необходимо указать после названия интерфейса:

Кроме общих интерфейсов, мы можем создавать общие классы.

Обратите внимание, что общие перечисления (enums) и пространства имен (namespaces) создавать нельзя.

Общие классы

Общий класс имеет такую же форму, что и общий интерфейс:

В случае с данным классом мы не ограничены числами. Мы вполне можем использовать строки или сложные объекты:

Класс имеет две стороны с точки зрения типов: статическую сторону и сторону экземпляров. Общие классы являются общими только для экземпляров. Это означает, что статические члены класса не могут использовать тип параметра класса.

Ограничения дженериков

Нам необходимо создать интерфейс, описывающий ограничение. В следующем примере мы создаем интерфейс с единственным свойством length и используем его с помощью ключевого слова extends для применения органичения:

Поскольку дженерик был ограничен, он больше не может работать с любым типом:

Мы должны передавать ему значения, отвечающие всем установленным требованиям:

Использование типов параметров в ограничениях дженериков

Мы можем определять типы параметров, ограниченные другими типами параметров. В следующем примере мы хотим получать свойства объекта по их названиям. При этом, мы хотим быть уверенными в том, что не извлекаем несуществующих свойств. Поэтому мы помещаем ограничение между двумя типами:

Использование типов класса в дженериках

При создании фабричных функций с помощью дженериков, необходимо ссылаться на типы классов через их функции-конструкторы. Например:

В более сложных случаях может потребоваться использование свойства prototype для вывода и ограничения отношений между функцией-конструктором и стороной экземляров типа класса:

Данный подход часто используется в миксинах или примесях.

Оператор типа keyof

Оператор keyof «берет» объектный тип и возвращает строковое или числовое литеральное объединение его ключей:

Типы keyof являются особенно полезными в сочетании со связанными типами (mapped types), которые мы рассмотрим позже.

Оператор типа typeof

В TS оператор typeof используется в контексте типа для ссылки на тип переменной или свойства:

Запомните: значения и типы — это не одно и тоже. Для ссылки на тип значения f следует использовать typeof :

Ограничения

typeof можно использовать только в отношении идентификаторов (названий переменных) или их свойств. Это помогает избежать написания кода, который не выполняется:

Типы доступа по индексу (indexed access types)

Мы можем использовать тип доступа по индексу для определения другого типа:

Индексированный тип — это обычный тип, так что мы можем использовать объединения, keyof и другие типы:

При попытке доступа к несуществующему свойству возникает ошибка:

Другой способ индексации заключается в использовании number для получения типов элементов массива. Мы также можем использовать typeof для перехвата типа элемента:

Однако, в данном случае мы можем использовать синоним типа (type alias):

Условные типы (conditional types)

Обычно, в программе нам приходится принимать решения на основе некоторых входных данных. В TS решения также зависят от типов передаваемых аргументов. Условные типы помогают описывать отношения между типами входящих и выходящих данных.

В приведенном примере польза условных типов не слишком очевидна. Она становится более явной при совместном использовании условных типов и дженериков (общих типов).

Рассмотрим такую функцию:

Перегрузки createLabel описывают одну и ту же функцию, которая делает выбор на основе типов входных данных.

Обратите внимание на следующее:

Вместо этого, мы можем реализовать такую же логику с помощью условных типов:

Затем мы можем использовать данный тип для избавления от перегрузок:

Ограничения условных типов

Часто проверка в условном типе дает нам некоторую новую информацию. Подобно тому, как сужение с помощью защитников или предохранителей типа (type guards) возвращает более конкретный тип, инстинная ветка условного типа ограничивает дженерики по типу, который мы проверяем.

Рассмотрим такой пример:

Предположения в условных типах

Мы использовали условные типы для применения ограничений и извлечения типов. Это является настолько распространенной операцией, что существует особая разновидность условных типов.

В данном случае мы использовали ключевое слово infer для декларативного создания нового дженерика Item вместо извлечения типа элемента T в истинной ветке. Это избавляет нас от необходимости «копаться» и изучать структуру типов, которые нам необходимы.

При предположении на основе типа с помощью нескольких сигнатур вызова (такого как тип перегруженной функции), предположение выполняется на основе последней сигнатуры. Невозможно произвести разрешение перегрузки на основе списка типов аргументов.

Распределенные условные типы (distributive conditional types)

Когда условные типы применяются к дженерикам, они становятся распределенными при получении объединения (union). Рассмотрим следующий пример:

Здесь StrOrNumArray распределяется на:

и применяется к каждому члену объединения:

что приводит к следующему:

Обычно, такое поведение является ожидаемым. Для его изменения можно обернуть каждую сторону extends в квадратные скобки:

Связанные типы (mapped types)

Связанные типы основаны на синтаксисе сигнатуры доступа по индексу, который используется для определения типов свойств, которые не были определены заранее:

Модификаторы связывания (mapping modifiers)

Повторное связывание ключей с помощью as

В TS 4.1 и выше, можно использовать оговорку as для повторного связывания ключей в связанном типе:

Для создания новых названий свойств на основе предыдущих можно использовать продвинутые возможности, такие как типы шаблонных литералов (см. ниже):

Ключи можно фильтровать с помощью never в условном типе:

Связанные типы хорошо работают с другими возможностями по манипуляции типами, например, с условными типами. В следующем примере условный тип возвращает true или false в зависимости от того, содержит ли объект свойство pii с литерально установленным true :

Типы шаблонных литералов (template literal types)

Типы шаблонных литералов основаны на типах строковых литералов и имеют возможность превращаться в несколько строк через объединения.

Когда тип используется в интерполированной позиции, он является набором каждого возможного строкого литерала, который может быть представлен каждым членом объединения:

Для каждой интерполированной позиции в шаблонном литерале объединения являются множественными:

Большие строковые объединения лучше создавать отдельно, но указанный способ может быть полезным в простых случаях.

Строковые объединения в типах

Мощь шаблонных строк в полной мере проявляется при определении новой строки на основе существующей внутри типа.

Шаблонные литералы предоставляют способ обработки такой операции внутри системы типов:

При передаче неправильного свойства возникает ошибка:

Предположения типов с помощью шаблонных литералов

Мы можем переписать последний пример с дженериком таким образом, что типы будут предполагаться на основе частей строки eventName :

Здесь мы реализовали on в общем методе.

Внутренние типы манипуляций со строками (intrisic string manipulation types)

Вот как эти типы реализованы:

Облачные серверы от Маклауд быстрые и безопасные.

Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *