Как различные варианты перечисления работают в TypeScript?
TypeScript имеет множество различных способов определения перечисления:
enum Alpha { X, Y, Z }
const enum Beta { X, Y, Z }
declare enum Gamma { X, Y, Z }
declare const enum Delta { X, Y, Z }
если я попытаюсь использовать значение из Gamma во время выполнения, я получаю сообщение об ошибке, потому что Gamma не определено, но это не относится к Delta или Alpha? Что значит const или declare имею в виду на декларациях здесь?
есть еще preserveConstEnums флаг компилятора -- как это взаимодействует с этим?
2 ответов:
есть четыре различных аспекта перечислений в TypeScript, о которых вы должны знать. Во-первых, некоторые определения:
"объект поиска"
если вы пишете это перечисление:
enum Foo { X, Y }TypeScript выдаст следующий объект:
var Foo; (function (Foo) { Foo[Foo["X"] = 0] = "X"; Foo[Foo["Y"] = 1] = "Y"; })(Foo || (Foo = {}));я буду называть это объект поиска. Его цель двоякая: служить отображением из строки до цифры, например, при написании
Foo.XилиFoo['X'], и служить в качестве отображения от цифры до строки. Это обратное сопоставление полезно для отладки или ведения журнала - вы часто будете иметь значение0или1и хотите получить соответствующую строку"X"или"Y"."объявить" или " ambient"
в TypeScript вы можете "объявлять" вещи, о которых компилятор должен знать, но на самом деле не выдавать код для. Это полезно, когда у вас есть библиотеки, такие как jQuery, которые определяют некоторый объект (например,
$), что вы хотите ввести информацию о, но не нужно никакого кода, созданного компилятором. Спецификация и другая документация относятся к объявлениям, сделанным таким образом, как находящимся в" окружающем " контексте; важно отметить, что все объявления в.d.tsфайл является "окружающим" (либо требует явногоdeclareмодификатор или неявно, в зависимости от декларации тип.)"inlining"
по причинам производительности и размера кода часто предпочтительно иметь ссылку на элемент перечисления, замененный его числовым эквивалентом при компиляции:
enum Foo { X = 4 } var y = Foo.X; // emits "var y = 4";спецификация называет это замена, я назову его inlining потому что это звучит круче. Иногда вы будете не хотите, чтобы элементы перечисления были встроены, например, потому что значение перечисления может измениться в a будущая версия API.
перечисления, как они работают?
давайте разберем это по каждому аспекту перечисления. К сожалению, каждый из этих четырех разделов будет ссылаться на термины из всех остальных, поэтому вам, вероятно, придется прочитать все это несколько раз.
вычисляется против не вычисляется (константа)
перечисление членов может быть либо вычисляемые или нет. Спецификация вызывает не вычисляемые члены постоянный, но я буду называть их невычисляемые чтобы избежать путаницы с const.
A вычисляемые элемент перечисления - это тот, значение которого неизвестно во время компиляции. Ссылки на вычисляемые члены не могут быть встроены, конечно. И наоборот, a невычисляемые перечисление член один раз чье значение и известен во время компиляции. Ссылки на не вычисляемые члены всегда встроены.
что члены перечисления вычисляются, а какие не вычисляются? Во-первых, все члены
constперечисления являются постоянными (т. е. не вычисляются), как следует из названия. Для неконстантного перечисления это зависит от того, смотрите ли вы на ambient (объявлять) перечисление или не перечисление окружающей среды.член a
declare enum(т. е. окружающее перечисление) является постоянным если и только если он имеет инициализатор. В противном случае он вычисляется. Обратите внимание, что вdeclare enum, только числовые инициализаторы допустимый. Пример:declare enum Foo { X, // Computed Y = 2, // Non-computed Z, // Computed! Not 3! Careful! Q = 1 + 1 // Error }наконец, члены не объявленных неконстантных перечислений всегда считаются вычисленными. Однако их инициализирующие выражения сводятся к константам, если они вычислимы во время компиляции. Это означает, что неконстантные элементы перечисления никогда не вставляются (это поведение изменилось в TypeScript 1.5, см." изменения в TypeScript " внизу)
константный против неконстантной
const
перечисление объявление может иметь
constмодификатор. Если перечислимый составляетconst,все ссылки на его членов встроены.const enum Foo { A = 4 } var x = Foo.A; // emitted as "var x = 4;", alwaysперечисления const не создают объект поиска при компиляции. По этой причине, это-ошибка ссылка
Fooв приведенном выше коде, за исключением как часть ссылки на элемент. Нет
здесь происходит несколько вещей. Давайте разберемся в каждом конкретном случае.
перечисление
enum Cheese { Brie, Cheddar }во-первых, просто перечисление. При компиляции в JavaScript, это будет выдавать таблицу подстановки.
таблица поиска выглядит так:
var Cheese; (function (Cheese) { Cheese[Cheese["Brie"] = 0] = "Brie"; Cheese[Cheese["Cheddar"] = 1] = "Cheddar"; })(Cheese || (Cheese = {}));тогда, когда у вас есть
Cheese.Brieв TypeScript, он испускаетCheese.Brieв JavaScript, который оценивается в 0.Cheese[0]выдаетCheese[0]и на самом деле оценивает в"Brie".const перечисление
const enum Bread { Rye, Wheat }никакой код на самом деле не испускается для этого! Его значения встроены. Следующие выделяют само значение 0 в JavaScript:
Bread.Rye Bread['Rye']
const enums' встраивание может быть полезно по соображениям производительности.а насчет
Bread[0]? Это будет ошибка во время выполнения и ваш компилятор должен поймать его. Там нет таблицы подстановки и компилятор не встроен здесь.обратите внимание, что в приведенном выше случае флаг --preserveConstEnums будет заставьте хлеб выдавать таблицу подстановки. Однако его значения все равно будут встроены.
объявить перечислимый
как и в других случаях использования
declare,declareвыделяет код и ожидает, что вы определили фактический код в другом месте. Это не выдает таблицу поиска:declare enum Wine { Red, Wine }
Wine.RedвыдаетWine.Redв JavaScript, но не будет никакой таблицы поиска вина для ссылки, поэтому это ошибка, если вы не определили ее в другом месте.объявить const перечисление
это не выдает таблицу поиска:
declare const enum Fruit { Apple, Pear }но он делает встроенный!
Fruit.Appleвыдает 0. Но опятьFruit[0]будет ошибка во время выполнения, потому что он не встроен и нет таблицы подстановки.Я написал это в этой детская площадка. Я рекомендую играть там, чтобы понять, какой TypeScript испускает какой JavaScript.
Comments