Ниже вольный пересказ оригинала статьи, которая показывает некоторые особенности Enum в Typescript. Итак, у нас есть enum, значениями которого являются числа number:
enum PackStatusNumber {
Draft = 0,
Approved = 1,
Shipped = 2,
}
… и есть enum, значениями которого являются строки string:
enum PackStatusString {
Draft = "Draft",
Approved = "Approved",
Shipped = "Shipped",
}
Ниже рассмотрим несколько особенностей поведения enum в Typescript.
Сколько ключей в объекте Link to heading
Давайте подумаем, сколько ключей имеют enum PackStatusNumber и PackStatusString? Если вывести ключи enum PackStatusString:
const logStatusString = (status: PackStatusString) => {
console.log(status);
};
console.log(Object.keys(PackStatusString));
… то получим ожидаемый результат - три ключа:
(3) ["Draft", "Approved", "Shipped"]
0:"Draft"
1:"Approved"
2:"Shipped"
… но если сделаем тоже самое для enum PackStatusNumber:
const logStatusNumber = (status: PackStatusNumber) => {
console.log(status);
};
console.log(Object.keys(PackStatusNumber));
… то результат будет - шесть(!) ключей:
(6) ["0", "1", "2", "Draft", "Approved",...]
0:"0"
1:"1"
2:"2"
3:"Draft"
4:"Approved"
5:"Shipped"
… это происходит потому, что Typescript в данном случае создает для каждого ключа объекта две пары - value-to-key и key-to-value!
Проверка типа Link to heading
Посмотрим, как работает проверка типа в Typescript применительно к enum.
Такой вариант передачи параметра в функцию - выполнится без ошибок:
logStatusString(PackStatusString.Approved);
… но если попробовать передать как аргумент - строку (даже если это - значение enum’а):
logStatusString('Approved');
… получим ошибку типизации - BugFinder: Argument of type '"Approved"' is not assignable to parameter of type 'PackStatusString'; но вот если тоже самое - сделать для числового enum PackStatusNumber:
logStatusNumber(1);
… то ошибки не получим! Странное поведение.
Один enum вместо другого Link to heading
Typescript не позволяет использовать один enum вместо другого, даже если ключи у них - одинаковые. Допустим, создадим два таких enum - один PackStatusString уже был у нас, а второй PackStatusStringSingle будет таким:
enum PackStatusString {
Draft = "Draft",
Approved = "Approved",
Shipped = "Shipped",
}
enum PackStatusStringSingle {
Draft = "Draft"
}
… и попробуем подставить PackStatusStringSingle вместо PackStatusString:
logStatusString(PackStatusStringSingle.Draft);
… Typescript выдаст ошибку типизации - BugFinder: Argument of type 'PackStatusStringSingle' is not assignable to parameter of type 'PackStatusString'.
И даже если - сделать второй enum PackStatusStringLink - как ссылку на первый enum PackStatusString:
enum PackStatusString {
Draft = "Draft",
Approved = "Approved",
Shipped = "Shipped",
}
enum PackStatusStringLink {
Draft = PackStatusString.Draft
}
… то все равно:
logStatusString(PackStatusStringLink.Draft);
… получим ошибку типизации - BugFinder: Argument of type 'PackStatusStringLink' is not assignable to parameter of type 'PackStatusString'. Логичное поведение.
Итог Link to heading
Как подведение итога всему вышеописанному, автор статьи делает следующий вывод:
Если я увидел перечисление в кодовой базе, я вряд ли от него избавлюсь. Но я бы не стал добавлять перечисление в новую кодовую базу. Если вы отчаянно нуждаетесь в перечислениях, я настоятельно рекомендую использовать только строковые перечисления. Они явны, ведут себя как перечисления и больше похожи на транспилированный код.