Разница между перечислениями строк и строковыми литералами в TS
Предполагая, что я хочу убедиться, что myKey
в { myKey: '' }
содержит только строки foo
, bar
, baz
, я мог бы достичь этого двумя способами.
// with a String Literal Type
type MyKeyType = 'foo' | 'bar' | 'baz';
// or with a String Enum
enum MyKeyType {
FOO = 'foo',
BAR = 'bar',
BAZ = 'baz'
}
Интересно, где все плюсы и минусы одного над другим, так как оба выглядят одинаково для меня (кроме того, как я мог бы получить доступ к значениям, например, при проверке состояния).
Единственное отличие, которое я нашел в документации TS: Enums - это реальные объекты во время выполнения, что может быть желательно в некоторых случаях.
Ответы
Ответ 1
Главное, чтобы понять, что значения перечислений строк непрозрачны.
Предполагаемый прецедент для перечисления строк состоит в том, что вы не хотите, чтобы другой код знал или заботился о том, что поддерживает литеральная строка MyKeyType.FOO
. Это означает, что вы не сможете, скажем, передать MyKeyType
строку "bar"
функции, принимающей MyKeyType.BAR
вместо этого вам придется писать MyKeyType.BAR
.
Ответ 2
Одним из преимуществ перечисления во время разработки является то, что вы легко увидите список опций с помощью intellisense:
Точно так же вы можете легко изменить значение перечисления, используя инструменты рефакторинга, вместо того, чтобы везде менять строку.
Редактировать: В VS 2017 и последней версии TypeScript intellisense работает со строковыми литералами:
Ответ 3
Что ж, есть разница между строковыми перечислениями и литеральными типами в переданном коде.
Сравните код Typescript
// with a String Literal Type
type MyKeyType1 = 'foo' | 'bar' | 'baz';
// or with a String Enum
enum MyKeyType2 {
FOO = 'foo',
BAR = 'bar',
BAZ = 'baz'
}
С переданным кодом JavaScript
// or with a String Enum
var MyKeyType2;
(function (MyKeyType2) {
MyKeyType2["FOO"] = "foo";
MyKeyType2["BAR"] = "bar";
MyKeyType2["BAZ"] = "baz";
})(MyKeyType2 || (MyKeyType2 = {}));
Что вы можете видеть, так это то, что нет никакого сгенерированного кода для строкового литерала. Потому что Typescripts Transpiler использует только для безопасности типов при переносе. Во время выполнения строковые литералы "генерируются в тупые" строки. Нет ссылок между определением литерала и употреблениями.
Таким образом, существует третья альтернатива, называемая const enum
Посмотри на это
// with a String Literal Type
type MyKeyType1 = 'foo' | 'bar' | 'baz';
// or with a String Enum
enum MyKeyType2 {
FOO = 'foo',
BAR = 'bar',
BAZ = 'baz'
}
// or with a Const String Enum
const enum MyKeyType3 {
FOO = 'foo',
BAR = 'bar',
BAZ = 'baz'
}
var a : MyKeyType1 = "bar"
var b: MyKeyType2 = MyKeyType2.BAR
var c: MyKeyType3 = MyKeyType3.BAR
будет перенесен в
// or with a String Enum
var MyKeyType2;
(function (MyKeyType2) {
MyKeyType2["FOO"] = "foo";
MyKeyType2["BAR"] = "bar";
MyKeyType2["BAZ"] = "baz";
})(MyKeyType2 || (MyKeyType2 = {}));
var a = "bar";
var b = MyKeyType2.BAR;
var c = "bar" /* BAR */;
Для дальнейшей игры вы можете проверить эту ссылку
Я предпочитаю const enum case из-за удобного способа ввода Enum.Value. Typescript сделает все возможное, чтобы получить максимальную производительность при переносе.