TypeScript bietet verschiedene Möglichkeiten, eine Aufzählung zu definieren:
enum Alpha { X, Y, Z }
const enum Beta { X, Y, Z }
declare enum Gamma { X, Y, Z }
declare const enum Delta { X, Y, Z }
Wenn ich versuche, einen Wert von Gamma
zur Laufzeit zu verwenden, wird eine Fehlermeldung angezeigt, da diese Gamma
nicht definiert ist. Dies ist jedoch nicht der Fall für Delta
oder Alpha
? Was bedeutet const
oder declare
bedeutet dies auf den Erklärungen hier?
Es gibt auch ein preserveConstEnums
Compiler-Flag - wie interagiert dies mit diesen?
enums
typescript
Ryan Cavanaugh
quelle
quelle
Antworten:
Aufzählungen in TypeScript haben vier verschiedene Aspekte, die Sie beachten müssen. Zunächst einige Definitionen:
"Suchobjekt"
Wenn Sie diese Aufzählung schreiben:
TypeScript gibt das folgende Objekt aus:
Ich werde dies als Suchobjekt bezeichnen . Sein Zweck ist zweifach: als Abbildung von dienen Strings zu Zahlen , zum Beispiel beim Schreiben
Foo.X
oderFoo['X']
, und als eine Abbildung von dienen Zahlen zu Strings . Diese umgekehrte Zuordnung ist nützlich für Debugging- oder Protokollierungszwecke - Sie haben häufig den Wert0
oder1
und möchten die entsprechende Zeichenfolge"X"
oder erhalten"Y"
."deklarieren" oder " umgebungs "
In TypeScript können Sie Dinge "deklarieren", über die der Compiler Bescheid wissen sollte, für die er jedoch keinen Code ausgibt. Dies ist nützlich, wenn Sie Bibliotheken wie jQuery haben, die ein Objekt definieren (z. B.
$
), zu dem Sie Typinformationen wünschen, aber keinen vom Compiler erstellten Code benötigen. Die Spezifikation und andere Dokumentationen beziehen sich auf Erklärungen, die auf diese Weise abgegeben wurden und sich in einem "Umgebungs" -Kontext befinden. Es ist wichtig zu beachten, dass alle Deklarationen in einer.d.ts
Datei "ambient" sind (declare
je nach Deklarationstyp entweder einen expliziten Modifikator erforderlich oder implizit)."Inlining"
Aus Gründen der Leistung und der Codegröße ist es häufig vorzuziehen, beim Kompilieren einen Verweis auf ein Enum-Mitglied durch sein numerisches Äquivalent zu ersetzen:
Die Spezifikation nennt diese Substitution , ich werde sie Inlining nennen, weil sie cooler klingt. Manchmal möchten Sie nicht, dass Enum-Mitglieder eingefügt werden, z. B. weil sich der Enum-Wert in einer zukünftigen Version der API möglicherweise ändert.
Enums, wie funktionieren sie?
Lassen Sie uns dies nach jedem Aspekt einer Aufzählung aufschlüsseln. Leider wird in jedem dieser vier Abschnitte auf Begriffe aus allen anderen Abschnitten verwiesen, sodass Sie diese ganze Sache wahrscheinlich mehr als einmal lesen müssen.
berechnet gegen nicht berechnet (konstant)
Enum-Mitglieder können entweder berechnet werden oder nicht. Die Spezifikation nennt nicht berechnete Mitglieder konstant , aber ich werde sie nicht berechnet nennen , um Verwechslungen mit const zu vermeiden .
Ein berechnetes Enum-Mitglied ist eines, dessen Wert zur Kompilierungszeit nicht bekannt ist. Verweise auf berechnete Mitglieder können natürlich nicht eingefügt werden. Umgekehrt ist ein nicht berechnetes Enum-Mitglied einmal vorhanden, dessen Wert zur Kompilierungszeit bekannt ist . Verweise auf nicht berechnete Mitglieder werden immer eingefügt.
Welche Enum-Mitglieder werden berechnet und welche nicht berechnet? Erstens sind alle Mitglieder einer
const
Aufzählung konstant (dh nicht berechnet), wie der Name schon sagt. Bei einer nicht konstanten Aufzählung hängt es davon ab, ob Sie eine Umgebungsaufzählung (deklarieren) oder eine nicht umgebungsbezogene Aufzählung betrachten.Ein Mitglied einer
declare enum
(dh Umgebungsaufzählung) ist genau dann konstant, wenn es einen Initialisierer hat. Andernfalls wird es berechnet. Beachten Sie, dass in adeclare enum
nur numerische Initialisierer zulässig sind. Beispiel:Schließlich gelten Mitglieder von nicht deklarierten Nicht-Konstanten-Aufzählungen immer als berechnet. Ihre initialisierenden Ausdrücke werden jedoch auf Konstanten reduziert, wenn sie zur Kompilierungszeit berechenbar sind. Dies bedeutet, dass nicht konstante Enum-Mitglieder niemals inline sind (dieses Verhalten wurde in TypeScript 1.5 geändert, siehe "Änderungen in TypeScript" unten).
const vs non-const
const
Eine Enum-Deklaration kann den
const
Modifikator haben. Wenn eine Aufzählung vorhanden istconst
, werden alle Verweise auf ihre Mitglieder eingefügt.const enums erzeugen beim Kompilieren kein Lookup-Objekt. Aus diesem Grund ist es ein Fehler,
Foo
im obigen Code zu referenzieren , außer als Teil einer Mitgliedsreferenz. ZurFoo
Laufzeit ist kein Objekt vorhanden.non-const
Wenn eine Enum-Deklaration nicht über den
const
Modifikator verfügt, werden Verweise auf ihre Mitglieder nur dann eingefügt, wenn das Mitglied nicht berechnet wurde. Eine nicht konstante, nicht deklarierte Aufzählung erzeugt ein Suchobjekt.deklarieren (Umgebungs) vs nicht deklarieren
Ein wichtiges Vorwort ist, dass
declare
TypeScript eine ganz bestimmte Bedeutung hat: Dieses Objekt existiert woanders . Es dient zur Beschreibung vorhandener Objekte. Dasdeclare
Definieren von Objekten, die tatsächlich nicht existieren, kann schlimme Folgen haben. Wir werden diese später untersuchen.erklären
A
declare enum
gibt kein Suchobjekt aus. Verweise auf seine Mitglieder werden eingefügt, wenn diese Mitglieder berechnet werden (siehe oben zu berechnet oder nicht berechnet).Es ist wichtig , dass andere Formen der Bezugnahme auf eine zu beachten
declare enum
sind erlaubt, zum Beispiel ist dieser Code nicht ein Übersetzungsfehler , sondern wird zur Laufzeit fehlschlagen:Dieser Fehler fällt unter die Kategorie "Lüg den Compiler nicht an". Wenn Sie
Foo
zur Laufzeit kein Objekt mit dem Namen haben, schreiben Sie nichtdeclare enum Foo
!A unterscheidet
declare const enum
sich nicht von aconst enum
, außer im Fall von --preserveConstEnums (siehe unten).nicht deklarieren
Eine nicht deklarierte Aufzählung erzeugt ein Suchobjekt, wenn dies nicht der Fall ist
const
. Inlining ist oben beschrieben.--preserveConstEnums Flag
Dieses Flag hat genau einen Effekt: Nicht deklarierte Konstanten geben ein Suchobjekt aus. Inlining ist nicht betroffen. Dies ist nützlich zum Debuggen.
Häufige Fehler
Der häufigste Fehler ist die Verwendung eines,
declare enum
wenn ein regulärerenum
oderconst enum
angemessener wäre. Eine übliche Form ist folgende:Denken Sie an die goldene Regel: Niemals
declare
Dinge, die es eigentlich nicht gibt . Verwendenconst enum
Sie diese Option, wenn Sie immer Inlining möchten oderenum
wenn Sie das Suchobjekt möchten.Änderungen in TypeScript
Zwischen TypeScript 1.4 und 1.5 wurde das Verhalten geändert (siehe https://github.com/Microsoft/TypeScript/issues/2183 ), sodass alle Mitglieder von nicht deklarierten Nicht-Konstanten-Aufzählungen als berechnet behandelt werden, auch wenn Sie werden explizit mit einem Literal initialisiert. Dieses „Auftrennung aufzuheben , das Baby“, so zu sprechen, so dass das inlining Verhalten berechenbarer und sauberer das Konzept der Trennung
const enum
von regelmäßigenenum
. Vor dieser Änderung wurden nicht berechnete Mitglieder von Nicht-Konstanten-Enums aggressiver eingefügt.quelle
enum
Typen, danke!const
für deklarierte Aufzählungstypen zu erstellen .Hier sind ein paar Dinge los. Gehen wir von Fall zu Fall.
Aufzählung
Erstens eine einfache alte Aufzählung. Bei der Kompilierung mit JavaScript wird eine Nachschlagetabelle ausgegeben.
Die Nachschlagetabelle sieht folgendermaßen aus:
Wenn Sie dann
Cheese.Brie
in TypeScript haben, wird esCheese.Brie
in JavaScript ausgegeben, das mit 0 ausgewertet wird . Es wirdCheese[0]
ausgegebenCheese[0]
und tatsächlich mit ausgewertet"Brie"
.const enum
Hierfür wird eigentlich kein Code ausgegeben! Seine Werte sind inline. Folgendes gibt den Wert 0 selbst in JavaScript aus:
const enum
Das Inlining von s kann aus Leistungsgründen nützlich sein.Aber was ist mit
Bread[0]
? Dies tritt zur Laufzeit auf und Ihr Compiler sollte es abfangen. Es gibt keine Nachschlagetabelle und der Compiler wird hier nicht inline.Beachten Sie, dass im obigen Fall das Flag --preserveConstEnums dazu führt, dass Bread eine Nachschlagetabelle ausgibt. Seine Werte werden jedoch weiterhin eingefügt.
enum deklarieren
Wie bei anderen Verwendungen
declare
,declare
emittiert keinen Code und erwartet Sie den eigentlichen Code an anderer Stelle definiert haben. Dies gibt keine Nachschlagetabelle aus:Wine.Red
wirdWine.Red
in JavaScript ausgegeben, aber es gibt keine Wine-Nachschlagetabelle, auf die verwiesen werden kann. Es handelt sich also um einen Fehler, es sei denn, Sie haben ihn an anderer Stelle definiert.deklariere const enum
Dies gibt keine Nachschlagetabelle aus:
Aber es macht inline!
Fruit.Apple
gibt 0 aus.Fruit[0]
Wird aber zur Laufzeit erneut auftreten, da es nicht inline ist und keine Nachschlagetabelle vorhanden ist.Ich habe das auf diesem Spielplatz geschrieben. Ich empfehle, dort zu spielen, um zu verstehen, welches TypeScript welches JavaScript ausgibt.
quelle
Bread[0]
ein Compilerfehler ausgegeben : "Auf ein const enum-Mitglied kann nur mit einem Zeichenfolgenliteral zugegriffen werden."