Часто объединенные типы Union Type и перечисляемый тип Enum - это онди из способов обеспечения типобезопасности кода, в частности типизация ограниченного списка каких либо значений.
Они также оба хорошо работают с современными IDE предлагая в подсказках отфильтрованные значения.
Но бывает задаешься вопросом: что лучше использовать в той или иной ситуации?
Разница в размере кода
Объединенные типы не будут создавать какой либо дополнительный код.
Вот Простой пример:
Версия с Union Type
type VehicleTypeUnion = 'SUV' | 'SEDAN' | 'TRUCK';
const a: VehicleTypeUnion = 'SUV'
->
"use strict";
const a = 'SUV';
Версия с Enum
enum VehicleTypeEnum {
SUV,
SEDAN,
TRUCK,
}
const b: VehicleTypeEnum = VehicleTypeEnum.SUV
->
var VehicleTypeEnum;
(function (VehicleTypeEnum) {
VehicleTypeEnum[VehicleTypeEnum["SUV"] = 0] = "SUV";
VehicleTypeEnum[VehicleTypeEnum["SEDAN"] = 1] = "SEDAN";
VehicleTypeEnum[VehicleTypeEnum["TRUCK"] = 2] = "TRUCK";
})(VehicleTypeEnum || (VehicleTypeEnum = {}));
const b = VehicleTypeEnum.SUV;
Разные типы в списке значений
перечисляемый тип обычно описывается в виде числовых значений или в виде строковых.
// список
enum VehicleType1 {
SUV,
SEDAN,
TRUCK,
BUS,
MOTORCYCLE
}
// эквивалентный список
enum VehicleType2{
SUV = 0,
SEDAN = 1,
TRUCK = 2,
BUS = 3,
MOTORCYCLE = 4
}
// список со строковыми значениями
enum VehicleType3{
SUV = 'SUV',
SEDAN = 'SEDAN',
TRUCK = 'TRUCK',
BUS = 'BUS',
MOTORCYCLE = 'MOTORCYCLE'
}
->
"use strict";
// перечисляемый тип
var VehicleType1;
(function (VehicleType1) {
VehicleType1[VehicleType1["SUV"] = 0] = "SUV";
VehicleType1[VehicleType1["SEDAN"] = 1] = "SEDAN";
VehicleType1[VehicleType1["TRUCK"] = 2] = "TRUCK";
VehicleType1[VehicleType1["BUS"] = 3] = "BUS";
VehicleType1[VehicleType1["MOTORCYCLE"] = 4] = "MOTORCYCLE";
})(VehicleType1 || (VehicleType1 = {}));
// эквивалентный тип
var VehicleType2;
(function (VehicleType2) {
VehicleType2[VehicleType2["SUV"] = 0] = "SUV";
VehicleType2[VehicleType2["SEDAN"] = 1] = "SEDAN";
VehicleType2[VehicleType2["TRUCK"] = 2] = "TRUCK";
VehicleType2[VehicleType2["BUS"] = 3] = "BUS";
VehicleType2[VehicleType2["MOTORCYCLE"] = 4] = "MOTORCYCLE";
})(VehicleType2 || (VehicleType2 = {}));
// тип со строковыми значениями
var VehicleType3;
(function (VehicleType3) {
VehicleType3["SUV"] = "SUV";
VehicleType3["SEDAN"] = "SEDAN";
VehicleType3["TRUCK"] = "TRUCK";
VehicleType3["BUS"] = "BUS";
VehicleType3["MOTORCYCLE"] = "MOTORCYCLE";
})(VehicleType3 || (VehicleType3 = {}));
Первый тип мы описали без инициализирующих значений, его значения инициализируются автоматически, в зависимости от порядка, поэтому порядок значений менять опасно!
Это также накладывает ограничение, что мы не можем использовать тип с проинициализированными значениями и без:
enum VehicleType {
SUV = 'SUV',
SEDAN = 'SEDAN',
TRUCK = 'TRUCK',
BUS = 'BUS',
MOTORCYCLE
}
Выведет ошибку error TS1061: Enum member must have initializer.
Вам придется описать тип так:
enum VehicleType {
SUV = 'SUV',
SEDAN = 'SEDAN',
TRUCK = 'TRUCK',
BUS = 'BUS',
MOTORCYCLE = 0,
}
Union Type
Тут вы можете создавать объединения с другими типами значений, отличными от строк:
type VehicleType = 'SUV' | 'SEDAN' | 'TRUCK' | 0 | [];
Это дает вам дополнительную гибкость в определении типов. Однако такая дополнительная гибкость может привести к неожиданному поведению в коде при отсутствии четкого понимания типа переменной, которая может быть строкой, или числом, или массивом объектов и т.д.
Перебор значений
Перечисления - это объекты, где каждому ключу свойства может быть автоматически присвоено значение или строка на случай, если мы определим значение вручную. Следовательно, вы можете повторять значения свойств точно так же, как и любой другой объект:
export enum VehicleType {
SUV = 'SUV',
SEDAN = 'SEDAN',
TRUCK = 'TRUCK',
BUS = 'BUS',
MOTORCYCLE = 'MOTORCYCLE'
}
for (const type in VehicleType) {
console.log(type);
}
Object.keys(VehicleType).forEach((key) => {
console.log('key ', key);
})
Попытка сделать что-то подобное с union types приведет к ошибке при попытке выполнения кода
type VehicleType = 'SUV' | 'SEDAN' | 'TRUCK' | 'BUS' | 'MOTORCYCLE';
for (const type in VehicleType) {
// my logic in here
console.log(type);
}
Object.keys(VehicleType).forEach((key) => {
console.log('key ', key);
})
error TS2693: 'VehicleType' only refers to a type, but is being used as a value here.
Вывод
Если вам нужно будет выполнять итерации по набору значений, лучше всего использовать enums, но вы тем самым пожертвуете размером собранного кода.