TypeScript - Enums: A Beginner's Guide

Здравствуйте, будущие программисты! Сегодня мы окунёмся в奇妙ный мир перечислимых типов TypeScript. Не волнуйтесь, если вы ещё никогда не писали код — я буду вашим доброжелательным проводником в этом путешествии, как я делал это для countless студентов на протяжении многих лет преподавания. Итак, начнём!

TypeScript - Enums

Что такое перечислимые типы?

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

Числовые перечислимые типы

Числовые перечислимые типы являются наиболее распространённым типом перечислимых типов в TypeScript. Они как присвоение чисел вашим любимым супергероям.

enum Superheroes {
    Superman,
    Batman,
    WonderWoman,
    Flash
}

console.log(Superheroes.Superman);  // Вывод: 0
console.log(Superheroes.Batman);    // Вывод: 1
console.log(Superheroes.WonderWoman);  // Вывод: 2
console.log(Superheroes.Flash);     // Вывод: 3

В этом примере TypeScript автоматически присваивает числа, начиная с 0. Superman получает 0, Batman получает 1 и т.д. Это как будто они выстраиваются для группового фото, и мы даём им номера в зависимости от их положения!

Но что, если мы хотим начать с другого числа? Нет проблем! Мы можем сделать это:

enum Villains {
    Joker = 1,
    LexLuthor,
    Cheetah,
    ReverseFlash
}

console.log(Villains.Joker);        // Вывод: 1
console.log(Villains.LexLuthor);    // Вывод: 2
console.log(Villains.Cheetah);      // Вывод: 3
console.log(Villains.ReverseFlash); // Вывод: 4

Здесь мы сказали TypeScript начать счёт с 1 для Joker, и он автоматически продолжил для остальных.

Строковые перечислимые типы

Теперь представьте, что вам не нравятся числа и вы предпочитаете слова. Здесь на помощь приходят строковые перечислимые типы. Они как dando вашим питомцам прозвища!

enum PetNames {
    Dog = "BUDDY",
    Cat = "WHISKERS",
    Fish = "BUBBLES",
    Bird = "TWEETY"
}

console.log(PetNames.Dog);   // Вывод: "BUDDY"
console.log(PetNames.Cat);   // Вывод: "WHISKERS"
console.log(PetNames.Fish);  // Вывод: "BUBBLES"
console.log(PetNames.Bird);  // Вывод: "TWEETY"

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

Смешанные перечислимые типы

Иногда жизнь не ограничивается только числами или только строками — это смесь! Смешанные перечислимые типы как коробка с ассортиrovanыми конфетами — вы получите немного всего.

enum MixedBag {
    Number = 1,
    String = "STRING",
    AnotherNumber = 2
}

console.log(MixedBag.Number);        // Вывод: 1
console.log(MixedBag.String);        // Вывод: "STRING"
console.log(MixedBag.AnotherNumber); // Вывод: 2

Хотя это возможно, обычно рекомендуется stick к либо всем числам, либо всем строкам в Enum для последовательности.

Перечислимые типы в runtime

Одна из классных вещей в перечислимых типах — они существуют в runtime. Это означает, что вы можете использовать их в своём коде так же, как и любой другой объект!

enum Fruits {
    Apple,
    Banana,
    Orange
}

function getFruitName(fruit: Fruits): string {
    return Fruits[fruit];
}

console.log(getFruitName(Fruits.Apple));  // Вывод: "Apple"
console.log(getFruitName(Fruits.Banana)); // Вывод: "Banana"

Здесь мы используем Enum так, как будто это обычный объект JavaScript. Это как иметь магический словарь, который может переводить числа в названия фруктов!

Перечислимые типы в compile time

Перечислимые типы также блестят в compile time. Они помогают TypeScript находить ошибки до того, как ваш код даже запустится!

enum DaysOfWeek {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

let day: DaysOfWeek = DaysOfWeek.Monday;
day = DaysOfWeek.Friday;  // Этоfine

// day = "Monday";  // Ошибка: Тип '"Monday"' не может быть присвоен типу 'DaysOfWeek'.

TypeScript даст вам ошибку, если вы попытаетесь присвоить значение, которое не является частью Enum. Это как будто у вас есть strict охранник в клубе, который впускает только дни недели!

Внешние перечислимые типы

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

declare enum ExternalEnum {
    A = 1,
    B,
    C = 2
}

Ключевое слово declare как будто вы говорите: "Эй TypeScript, верь мне, этот Enum существует где-то в коде". Это полезно, когда вы работаете с кодом, который не написан на TypeScript.

Объекты vs. Перечислимые типы

Вы можете задаться вопросом: "Почему не просто использовать объекты?" Ну, перечислимые типы имеют некоторые преимущества:

// Использование объекта
const ColorObject = {
    Red: 'RED',
    Green: 'GREEN',
    Blue: 'BLUE'
} as const;

// Использование Enum
enum ColorEnum {
    Red = 'RED',
    Green = 'GREEN',
    Blue = 'BLUE'
}

// С объектами вам нужно использовать типовые утверждения
let objColor: keyof typeof ColorObject = 'Red';

// С Enum это более directamente
let enumColor: ColorEnum = ColorEnum.Red;

Перечислимые типы обеспечивают лучшую типовую безопасность и часто более кратки.

Использование Enum в качестве параметра функции

Перечислимые типы великолепны для параметров функций. Они делают ваш код более читаемым и предотвращают ошибки:

enum Sizes {
    Small,
    Medium,
    Large
}

function orderCoffee(size: Sizes): string {
    switch(size) {
        case Sizes.Small:
            return "Here's your small coffee!";
        case Sizes.Medium:
            return "One medium coffee coming right up!";
        case Sizes.Large:
            return "Large coffee, extra caffeine!";
        default:
            return "We don't have that size!";
    }
}

console.log(orderCoffee(Sizes.Medium));  // Вывод: "One medium coffee coming right up!"
// console.log(orderCoffee("Venti"));    // Ошибка: Аргумент типа '"Venti"' не может быть присвоен типу 'Sizes'.

Используя Enum для параметра размера, мы гарантируем, что только допустимые размеры могут быть переданы в функцию. Это как меню с фиксированными опциями — keine verwirrung über die verfügbaren Größen!

Методы Enum

Вот таблица полезных методов для работы с Enum:

Метод Описание Пример
Object.keys() Получить все ключи Enum Object.keys(Sizes)
Object.values() Получить все значения Enum Object.values(Sizes)
Object.entries() Получить пары ключ-значение Enum Object.entries(Sizes)
Enum[key] Получить значение для ключа Sizes[Sizes.Small]
Enum[value] Получить ключ для значения (для числовых Enum) Sizes[0]

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

И вот вы уже сделали свои первые шаги в мир перечислимых типов TypeScript. Помните, программирование — это как учить новый язык — это требует практики, но скоро вы будете свободно говорить на Enum-языке! Продолжайте программировать, stay curious и не забывайте получать удовольствие в процессе. Кто знает, может быть, в следующий раз вы создадите Enum для своих любимых вкусов мороженого!

Credits: Image by storyset