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
、これはこれらとどのように相互作用するのでしょうか?
ベストアンサー1
TypeScript の列挙型には、知っておくべき 4 つの異なる側面があります。まず、いくつかの定義を示します。
「ルックアップオブジェクト」
この列挙型を記述すると:
enum Foo { X, Y }
TypeScript は次のオブジェクトを生成します。
var Foo;
(function (Foo) {
Foo[Foo["X"] = 0] = "X";
Foo[Foo["Y"] = 1] = "Y";
})(Foo || (Foo = {}));
これをルックアップオブジェクトその目的は2つあります。文字列に数字Foo.X
、例えば、またはを書くときFoo['X']
、そしてからのマッピングとして機能する。数字に文字列この逆マッピングは、デバッグやログ記録の目的で役立ちます。多くの場合、値0
または があり、対応する文字列または を1
取得する必要があります。"X"
"Y"
"宣言する"または "周囲「
TypeScript では、コンパイラが認識する必要があるが、実際にはコードを出力しないものを「宣言」できます。これは、$
型情報が必要なオブジェクト (例 ) を定義する jQuery などのライブラリがあり、コンパイラによってコードが作成される必要がない場合に便利です。仕様およびその他のドキュメントでは、このようにして行われた宣言を「アンビエント」コンテキストにあると呼んでいます。ファイル内のすべての宣言が.d.ts
「アンビエント」である (declare
宣言タイプに応じて、明示的な修飾子を必要とするか、暗黙的に修飾子を持つ) ことに注意することが重要です。
「インライン化」
パフォーマンスとコード サイズの理由から、コンパイル時に enum メンバーへの参照をそれに相当する数値に置き換えることが望ましい場合がよくあります。
enum Foo { X = 4 }
var y = Foo.X; // emits "var y = 4";
仕様ではこれを代替私はそれを呼ぶことにするインライン化かっこいいから。ないたとえば、列挙値が API の将来のバージョンで変更される可能性があるため、列挙メンバーをインライン化する必要があります。
列挙型はどのように機能しますか?
列挙型の各側面について詳しく説明しましょう。残念ながら、これら 4 つのセクションはそれぞれ、他のすべてのセクションの用語を参照するため、全体を複数回読む必要があるでしょう。
計算値と非計算値(定数)
列挙型のメンバーは計算された仕様では非計算メンバーを絶え間ない、でも私は彼らを呼ぶつもりです計算されていない混同を避けるために定数。
あ計算されたenumメンバーはコンパイル時に値が分からないメンバーです。もちろん、計算メンバーへの参照はインライン化できません。逆に、計算されていないenumメンバーは、その値がはコンパイル時に認識されます。非計算メンバーへの参照は常にインライン化されます。
どの列挙型メンバーが計算型で、どのメンバーが非計算型か?まず、const
列挙型のメンバーはすべて定数(つまり非計算型)であり、その名前が示す通りです。非定数列挙型の場合、周囲(宣言) enum または非アンビエント enum。
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
定数
enum宣言にはconst
修飾子を付けることができます。enumが の場合const
、全てインライン化されたメンバーへの参照。
const enum Foo { A = 4 }
var x = Foo.A; // emitted as "var x = 4;", always
const enums は、コンパイル時にルックアップ オブジェクトを生成しません。このため、Foo
メンバー参照の一部以外として上記のコードで参照するとエラーになります。Foo
実行時にはオブジェクトは存在しません。
非定数
enum 宣言に修飾子がない場合const
、そのメンバーへの参照は、メンバーが非計算型の場合にのみインライン化されます。非 const 非宣言 enum は、ルックアップ オブジェクトを生成します。
宣言(アンビエント)と非宣言
重要な前置きは、declare
TypeScript では非常に具体的な意味を持つということです。このオブジェクトは別の場所に存在します. 記述するためのものです既存 オブジェクト。declare
実際には存在しないオブジェクトを定義するために を使用すると、悪い結果が生じる可能性があります。これについては後で説明します。
宣言する
A はdeclare enum
ルックアップ オブジェクトを生成しません。そのメンバーへの参照は、それらのメンバーが計算済みである場合はインライン化されます (計算済みと非計算済みについては上記を参照)。
他の形式の参照には注意が必要です。declare enum
は許可されています。例えば、このコードはないコンパイルエラーですが意思実行時に失敗する:
// Note: Assume no other file has actually created a Foo var at runtime
declare enum Foo { Bar }
var s = 'Bar';
var b = Foo[s]; // Fails
このエラーは、「コンパイラに嘘をつかないこと」のカテゴリに分類されます。実行時に名前が付けられたオブジェクトがない場合は、 !Foo
と記述しないでください。declare enum Foo
--preserveConstEnums の場合を除き、A はdeclare const enum
a と変わりません(以下を参照)。const enum
非宣言
宣言されていない列挙型は、そうでない場合はルックアップ オブジェクトを生成しますconst
。インライン化については上記で説明しました。
--preserveConstEnums フラグ
このフラグの効果は 1 つだけです。宣言されていない const 列挙型はルックアップ オブジェクトを生成します。インライン展開は影響を受けません。これはデバッグに役立ちます。
よくあるエラー
最も一般的な間違いは、declare enum
通常のenum
または の方const enum
が適切な場合に を使用することです。一般的な形式は次のとおりです。
module MyModule {
// Claiming this enum exists with 'declare', but it doesn't...
export declare enum Lies {
Foo = 0,
Bar = 1
}
var x = Lies.Foo; // Depend on inlining
}
module SomeOtherCode {
// x ends up as 'undefined' at runtime
import x = MyModule.Lies;
// Try to use lookup object, which ought to exist
// runtime error, canot read property 0 of undefined
console.log(x[x.Foo]);
}
黄金律を覚えておいてください:declare
実際には存在しないものは決してconst enum
常にインライン化が必要な場合、またはenum
ルックアップ オブジェクトが必要な場合に使用します。
TypeScriptの変更点
TypeScript 1.4と1.5の間で動作が変更されました(参考:) により、宣言されていない非定数列挙型のすべてのメンバーが、リテラルで明示的に初期化されている場合でも、計算済みとして扱われるようになりました。これは、いわば「赤ちゃんを分割解除」し、インライン化の動作をより予測可能にし、 の概念をconst enum
通常の からより明確に分離しますenum
。この変更の前は、非定数列挙型の非計算済みメンバーは、より積極的にインライン化されていました。