что такое enum typescript

Руководство по перечислению TypeScript

Перечисления (или перечисления) — это поддерживаемый тип данных в TypeScript. Перечисления используются в большинстве объектно-ориентированных языков программирования, таких как Java и C #, а теперь доступны и в TypeScript. Это одна из немногих функций TypeScript, которая не является расширением JavaScript на уровне типов. Перечисления позволяют определять набор именованных констант. Их использование упрощает документирование намерений или создание набора отдельных случаев. Сегодня мы рассмотрим основы перечислений TypeScript, а также варианты использования, различные типы перечислений и следующие шаги для вашего обучения.

Что такое enum в Typescript?

Перечисления TypeScript позволяют определять набор именованных констант. Их использование может упростить документирование намерений или создание набора отдельных случаев. Многие языки программирования, такие как C, C # и Java, имеют enumтип данных, а JavaScript — нет. Однако TypeScript делает. TypeScript имеет как числовые, так и строковые перечисления.

Синтаксис перечислений следующий:

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

Зачем использовать перечисления в TypeScript?

Перечисления — отличный способ организовать ваш код в TypeScript. Давайте посмотрим на некоторые плюсы:

Перечисления против альтернатив

Хотя использование перечислений TypeScript дает множество преимуществ, в некоторых случаях вам не следует их использовать, например:

Теперь давайте углубимся в некоторые типы перечислений.

Числовые перечисления

Числовые перечисления хранят строковые значения как числа. Их можно определить с помощью enumключевого слова. Допустим, вы хотите хранить набор разных типов автомобилей. В следующем примере показано числовое перечисление в TypeScript:

Значение перечисления CarTypeимеет четыре значения: Honda, Toyota, Subaru и Hyundai. Значения перечисления начинаются с нуля и увеличиваются на единицу для каждого члена, что будет выглядеть примерно так:

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

В приведенном выше примере мы инициализировали первый член Hondaчисловым значением, равным единице. Остальные числа будут увеличены на единицу.

Примечание : нет необходимости назначать последовательные значения вашим членам перечисления. Вы можете присвоить им любые значения, какие захотите.

Перечисления строк

Перечисления строк аналогичны числовым перечислениям, но их значения перечисления инициализируются строковыми значениями вместо числовых значений. Строковые перечисления лучше читаются, чем числовые, что упрощает отладку ваших программ.

В следующем примере используется та же информация, что и в примере числового перечисления, но она представлена ​​в виде строкового перечисления:

В этом примере мы определили строковое перечисление CarTypeс теми же значениями, что и числовое перечисление, за исключением того, что значения перечисления инициализируются как строковые литералы.

Примечание. Строковые значения перечисления необходимо инициализировать индивидуально.

Гетерогенные перечисления

Гетерогенные перечисления содержат как числовые, так и строковые значения. Вот пример:

Обратное отображение с перечислениями

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

Источник

Война с TypeScript или покорение Enum

Предыстория

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

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

Знакомство с проблемой

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

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

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

1. Декоратор

С чего начать? На ум приходило только одно: взять за основу Java-подобное перечисление. Но так как мне хотелось выпендриться перед коллегами, я решил отказаться от классического наследования. Вместо него воспользоваться декоратором. Декоратор к тому же, можно было бы применить с аргументами, для того, чтобы придать перечислениям требуемую функциональность легко и непринужденно. Кодинг не отнял много времени и через пару часиков я уже имел, что-то похожее на это:

И здесь меня постигла первая неудача. Оказалось, что с помощью декоратора нельзя изменить тип. На эту тему у Microsoft есть даже обращение: Class Decorator Mutation. Когда я говорю, что нельзя изменить тип, я имею ввиду, что Ваша IDE ничего об этом не узнает и никаких подсказок и адекватных автодополнений не предложит. А тип менять можно сколько угодно, только толку от этого…

2. Наследование

Как я не старался уговаривать самого себя, но мне пришлось вернуться к идее создания перечислений на базе общего класса. Да и что в этом такого? Я был раздосадован самим собой. Время то идет, парни из группы фигачат дай бог, а я тут на декораторы время трачу. Можно было вообще за час запилить enum и идти дальше. Значит так тому и быть. Быстро накидал код базового класса Enumerable и вздохнул, почувствовав облегчение. Закинул драфт в общий репозиторий и попросил коллегу проверить решение.

Но трагикомедия набирала полный ход. У меня на машине был установлен TypeScript версии 2.6.2, именно та версия, в которой имелся бесценный баг. Бесценный, потому что не баг, а фитча. Голос из соседней комнаты прокричал, что у него ничего не собирается. Ошибка при компиляции (транспиляции). Я не поверил собственным ушам, ибо всегда собираю проект, перед пушем, даже если это драфт. А внутренний голос прошептал: это фиаско, братан.

Читайте также:  что делать с накоплениями при девальвации рубля

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

В сухом остатке: проблема с перечислениями как была так и осталась. Моя печаль…

Примечание: не могу воспроизвести такое поведение у себя сейчас с 2.6.2, возможно с версией ошибся или чего-то не дописал в тестовых примерах. А запрос на описанную выше проблему Allow static members to reference class type parameters был отклонен.

3. Функция кастования

Несмотря на то, что кривое решение имелось, с явным указанием типа класса перечисления в статических методах, например так, State.valueOf (), оно никого не устраивало и прежде всего меня. На некоторое время я даже отложил в сторону долбаные перечисления и потерял уверенность в том, что вообще смогу решить эту проблему.

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

А само объявление Java-подобного перечисления теперь выглядит так:

Не обошлось и без курьеза, с лишним импортом IStaticEnum, который нигде не используется (см пример выше). В той самой злополучной версии TypeScript 2.6.2 нужно указывать его явно. Баг на тему здесь.

Итого

Если долго мучаться, что-нибудь получится. Ссылка на гитхаб с результатом проделанной работы здесь. Для себя я открыл, что TypeScript — это язык с большими возможностями. Этих возможностей так много, что в них можно утонуть. А кто не хочет идти ко дну, учится плавать. Если вернуться к теме перечислений, то можно увидеть как с ними работают другие:

Источник

Примитивный Тип Enum

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

TypeScript привносит новую синтаксическую конструкцию называемую Enum (перечисление). enum представляет собой набор логически связанных констант, в качестве значений которых могут выступать как числа, так и строки.

Enum (enum) примитивный перечисляемый тип

Перечисления с числовым значением

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

Также можно установить любое значение вручную.

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

Вдобавок ко всему enum позволяет задавать псевдонимы (alias). Псевдонимам устанавливается значение константы, на которую они ссылаются.

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

6 шаг. Теперь проделаем, то же самое для двух других констант.

7 шаг. Теперь превратим функции initialization в самовызывающееся функциональное выражение и лучше анонимное.

8 шаг. И перенесем инициализацию объекта прямо на место вызова.

Перечисление готово. Осталось сравнить созданное перечисление с кодом полученным в результате компиляции.

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

Перечисления со строковым значением

Но в случае, когда константам присваиваются строки, ассоциируется только ключ со значением. Обратная ассоциация (значение-ключ) — отсутствует. Простыми словами, по идентификатору (имени константы) можно получить строковое значение, но по строковому значению получить идентификатор (имя константы) невозможно.

Тем не менее остается возможность создавать псевдонимы (alias).

И снова изучим скомпилированный код. Можно убедится, что псевдонимы создаются так же, как и константы. А значение присваиваемое псевдонимам идентично значению констант на которые они ссылаются.

Смешанное перечисление (mixed enum)

Если в одном перечислении объявлены числовые и строковые константы, то такое перечисление называется смешанным (mixed enum).

Со смешанным перечислением связаны две неочевидные особенности.

Первая из них заключается в том, что константам, которым значение не задано явно, присваивается числовое значение по правилам перечисления с числовыми константами.

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

Перечисление в качестве типа данных

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

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

Поведение не совсем очевидное, поэтому не стоит забывать об этом при использовании перечислений в которых присутствуют константы с числовым значением в качестве типа.

Перечисление const с числовым и строковым значением

После компиляции от перечисления не остается и следа, так как константы будут заменены числовыми литералами. Такое поведение называется inline встраивание.

Тип enum является уникальным для TypeScript, в JavaScript подобного типа не существует.

Когда стоит применять enum?

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

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

Источник

Что такое enum typescript

Enums are one of the few features TypeScript has which is not a type-level extension of JavaScript.

Enums allow a developer to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases. TypeScript provides both numeric and string-based enums.

We’ll first start off with numeric enums, which are probably more familiar if you’re coming from other languages. An enum can be defined using the enum keyword.

Читайте также:  что надо делать если слоятся ногти на руках

If we wanted, we could leave off the initializers entirely:

Using an enum is simple: just access any member as a property off of the enum itself, and declare types using the name of the enum:

Numeric enums can be mixed in computed and constant members (see below). The short story is, enums without initializers either need to be first, or have to come after numeric enums initialized with numeric constants or other constant enum members. In other words, the following isn’t allowed:

String enums are a similar concept, but have some subtle runtime differences as documented below. In a string enum, each member has to be constant-initialized with a string literal, or with another string enum member.

Technically enums can be mixed with string and numeric members, but it’s not clear why you would ever want to do so:

Unless you’re really trying to take advantage of JavaScript’s runtime behavior in a clever way, it’s advised that you don’t do this.

Computed and constant members

Each enum member has a value associated with it which can be either constant or computed. An enum member is considered constant if:

It is the first member in the enum and it has no initializer, in which case it’s assigned the value 0 :

It does not have an initializer and the preceding enum member was a numeric constant. In this case the value of the current enum member will be the value of the preceding enum member plus one.

The enum member is initialized with a constant enum expression. A constant enum expression is a subset of TypeScript expressions that can be fully evaluated at compile time. An expression is a constant enum expression if it is:

In all other cases enum member is considered computed.

Union enums and enum member types

There is a special subset of constant enum members that aren’t calculated: literal enum members. A literal enum member is a constant enum member with no initialized value, or with values that are initialized to

When all members in an enum have literal enum values, some special semantics come to play.

The first is that enum members also become types as well! For example, we can say that certain members can only have the value of an enum member:

The other change is that enum types themselves effectively become a union of each enum member. With union enums, the type system is able to leverage the fact that it knows the exact set of values that exist in the enum itself. Because of that, TypeScript can catch bugs where we might be comparing values incorrectly. For example:

Enums are real objects that exist at runtime. For example, the following enum

can actually be passed around to functions

Enums at compile time

Even though Enums are real objects that exist at runtime, the keyof keyword works differently than you might expect for typical objects. Instead, use keyof typeof to get a Type that represents all Enum keys as strings.

In addition to creating an object with property names for members, numeric enums members also get a reverse mapping from enum values to enum names. For example, in this example:

TypeScript compiles this down to the following JavaScript:

Keep in mind that string enum members do not get a reverse mapping generated at all.

In most cases, enums are a perfectly valid solution. However sometimes requirements are tighter. To avoid paying the cost of extra generated code and additional indirection when accessing enum values, it’s possible to use const enums. Const enums are defined using the const modifier on our enums:

Const enums can only use constant enum expressions and unlike regular enums they are completely removed during compilation. Const enum members are inlined at use sites. This is possible since const enums cannot have computed members.

in generated code will become

Ambient enums are used to describe the shape of already existing enum types.

One important difference between ambient and non-ambient enums is that, in regular enums, members that don’t have an initializer will be considered constant if its preceding enum member is considered constant. In contrast, an ambient (and non-const) enum member that does not have initializer is always considered computed.

In modern TypeScript, you may not need an enum when an object with as const could suffice:

The biggest argument in favour of this format over TypeScript’s enum is that it keeps your codebase aligned with the state of JavaScript, and when/if enums are added to JavaScript then you can move to the additional syntax.

The TypeScript docs are an open source project. Help us improve these pages by sending a Pull Request ❤

Источник

TypeScript: основы

Что такое TypeScript?

TypeScript — один из языков программирования, получивший широкое признание в профессиональных кругах. Многие веб-разработчики отдают ему предпочтение и используют для создания новых программ. Краткий ответ на вопрос “Что такое TypeScript?” заложен в его названии: TypeScript — это язык программирования, реализовавший систему типов JavaScript. Иными словами, TypeScript — язык расширения возможностей JavaScript.

Почему мы используем TypeScript?

Зачем нам изучать другой язык, если JavaScript и без того достаточно сложен и многослоен? Что движет приверженцами TypeScript — подражание другим компаниям, взявшим на вооружение TypeScript, или просто дань моде на новейшие технологии?

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

Предотвращение ошибок

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

Давайте сравним два кода ниже и посмотрим, как TypeScript заранее предотвращает ошибки.

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

Добавим числа 10 и 20 с помощью функции add (). Ожидаемый результат, который мы должны получить, — 30.

Читайте также:  что нужно делать после открытия ооо 2021

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

Неверный результат JavaScript

Посмотрим теперь на код, написанный на TypeScript. Как видите, редактор кода Visual Studio Code уже предупреждает нас о том, что в аргумент функции вставлено неверное значение.

Автозаполнение кода и руководство

Еще одно преимущество TypeScript заключается в том, что он позволяет нам максимально использовать возможности инструмента разработки при написании кода. Visual Studio Code, который обычно используется в разработке клиентской части приложений, оптимизирован для работы в TypeScript, поскольку этот инструмент создан на основе TypeScript.

Давайте посмотрим на код JavaScript ниже и оценим преимущества добавления типа в JavaScript для разработчика.

Приведенный выше код использует функцию add (), ранее выведенную нами, чтобы получить результат как сумму двух чисел, а затем добавляет “toLocaleString() API”, где числа помечены в соответствии с выражением определенного языка. Не имеет значения, какую роль выполняет API под названием “toLocaleString ()”, но важно, что JavaScript не мог распознать во время написания кода, что тип общей переменной — число.

Другими словами, сами разработчики ожидают результата функции add (), а затем предполагают, что типом результата должно быть число, прежде чем писать код “toLocaleString ()”, чей API содержит число. Взгляните на этот процесс.

Как вы видели, тип общей переменной произвольный, поэтому я вводил данные поочередно, чтобы написать “toLocaleString ()”, чей API предоставляет JavaScript Number. Если бы я допустил опечатку и написал “toLocalString()”, заметить ошибку можно было бы только тогда, когда файл ex-1.js был бы запущен в браузере.

А что произойдет, если код будет написан в TypeScript, как показано ниже?

Поскольку тип уже указан для общей переменной, Visual Studio Code может предварительно просматривать API для этого типа, поэтому позволяет быстро и точно записать API с помощью вкладок, а не вводить данные поочередно.

Number

String

Boolean

Undefined и Null

Типы Undefined и Null редко бывают необходимы сами по себе, однако становятся полезными при использовании с типом Union.

Unknown и Any

Лучше не допускать использования типов Unknown и Any в TypeScript, чтобы избежать создания кода, характерного для JavaScript.

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

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

Never

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

Object

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

Array

Tuple

Tuple представляет собой массив с элементами разных типов. Не стоит его использовать опрометчиво, кроме как для написания интерфейсов, псевдонимных типов или классов, потому что они менее разборчивы для чтения. Однако Tuple может быть полезен, если что-то возвращается в динамичном режиме, есть неоднозначный запрос в классе или интерфейсе, и пользователь определяет и записывает имя, группируя другие типы динамически связанных данных. Tulpe часто используется в React-хуках.

Alias

Если необходимо определить ваш собственный тип, вы можете использовать тип Alias.

Можно определить примитивные типы, а также типы форм объектов.

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

Union

Это тип, который означает A или B подобно OR-оператору “||” в JavaScript. Таким образом, тип Union лучше использовать в случае, когда нужно определить место только для одного из всех возможных случаев.

Функция move (), реализованная выше, может принимать в качестве факторов только аргументы, объявленные в типе Direction.

Приведенный выше код не вызывает ошибок, но рекомендуется использовать тип Discriminated Union, описанный ниже.

Discriminated Union

Тип Discriminated Union означает присвоение общего ключа, предназначенного для совместного использования внутри типа Union.

Тип Discrimination Union, пример которого приводится выше, позволяет более интуитивно писать код для приложения.

Intersection

Если в типе Union реализуется концепция “OR” (“ИЛИ”), то в типе Intersection — концепция “AND” (“И”).

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

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

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

В JavaScript API под названием freeze() может использоваться для придания объектам вида Enum, чтобы константы можно было сгруппировать и определить только один раз во избежание изменений.

Однако в TypeScript при объявлении Enum заглавными буквами пишется только первая буква, а не полностью все имя переменной.

Если начальное значение не задано, как показано в приведенном выше коде, оно увеличится на единицу от нуля.

Не рекомендуется часто использовать тип Enum в TypeScript, поскольку он может присваивать значения, отличные от Enum, даже если переменной Enum уже присвоен.

По этой причине в TypeScript тип Union используется чаще, чем Enum. Однако, когда необходимо обмениваться данными с другими языками, например, если веб-приложению и мобильному приложению необходимо взаимодействовать друг с другом, тип Union не может быть распознан на других языках, поэтому приходится использовать тип Enum.

Inference

TypeScript может самоопределиться, если тип не указан в переменной или функции.

TypeScript проверяет данные, присвоенные переменной, и считает текст переменной типом String, если он не объявляет String, как показано в приведенном ниже коде.

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

Assertion

TypeScript позволяет переопределять Inference любым удобным для вас способом. Тип Assertion обычно используется для переноса кода из JavaScript, что рекомендуется, когда вы точно знаете тип возвращаемой функции или тип переменной. Если тип прогнозирования неопределен и вы его используете, ошибок во время компиляции и при написании кода не будет, но вы увидите неожиданные результаты в веб-браузере.

Обучение

Посмотрите это видео и поучитесь реализовать простую функцию calculate() с использованием вышеперечисленных типов.

Источник

Строительный портал