TypeScript 列挙型

Enum は TypeScript の新しいデータ構造および型であり、中国語では「列挙」と訳されます。

導入

実際の開発では、多くの場合、関連する定数のセットを定義する必要があります。

定数RED = 1;
const 緑 = 2;
定数青 = 3;

let color = userInput();

if (色 === レッド) {/* */}
if (色 === 緑) {/* */}
if (色 === ブルー) {/* */}

throw new Error('wrong color');

上記の例では、定数 REDGREEN、および BLUE が関連付けられており、これは変数 color の 3 つの可能な値を意味します。等しくない限り、それらがどのような値に等しいかは問題ではありません。

TypeScript は、使いやすいように関連する定数をコンテナーに配置するように Enum 構造を設計しました。

列挙型の色 {
  赤、// 0
  緑、// 1
  青 // 2
}

上の例では、Enum 構造体 Color を宣言しています。これには 3 つのメンバー RedGreenBlue が含まれています。最初のメンバーの値のデフォルトは整数 '0'、2 番目の値は '1'、3 番目の値は '2' などとなります。

Enum のメンバーの呼び出しは、オブジェクト プロパティの呼び出しと同じ方法で記述されます。ドット演算子または角括弧演算子を使用できます。

let c = Color.Green // 1
// と同等
let c = Color['Green']; // 1

Enum 構造体自体も型です。たとえば、上の例の変数 c1 に等しく、その型は Color または number にすることができます。

let c:Color = Color.Green // 修正します。
let c:number = Color.Green // 修正します。

上の例では、変数 c の型は Color または number として記述できます。ただし、「Color」タイプの方がセマンティクスが優れています。

Enum 構造体の特別な点は、それが型でもあり、値でもあることです。ほとんどの TypeScript 構文は型構文であり、コンパイル後に削除されます。ただし、Enum 構造は値であり、コンパイル後に JavaScript オブジェクトになり、コードに残ります。

// コンパイル前
列挙型の色 {
  赤、// 0
  緑、// 1
  青 // 2
}

//コンパイル後
カラー = { にします
  赤:0、
  緑: 1、
  青:2
};

上記の例は、コンパイル前とコンパイル後の Enum 構造の比較です。

TypeScript は JavaScript 言語の型拡張として位置付けられているため、Enum 構造体は型であるだけでなく、コンパイルされたコードにオブジェクトを追加するため、慎重に使用することが公式に推奨されています。

Enum 構造は、メンバーの値は重要ではないが、名前の方が重要であるシナリオに適しており、コードの可読性と保守性が向上します。

列挙演算子 {
  追加、
  ディビジョン、
  マル、
  サブ
}

関数の計算(
  オペレーター:オペレーター、
  a:数字、
  b:数字
) {
  スイッチ (オプション) {
    case 演算子.ADD:
      a + b を返します。
    case 演算子.DIV:
      a / b を返します。
    case 演算子.MUL:
      a * b を返します。
    case 演算子.SUB:
      a - b を返します。
    デフォルト:
      throw new Error('間違った演算子');
  }
}

compute(Operator.ADD, 1, 3) // 4

上記の例では、Enum 構造体「Operator」の 4 つのメンバーが「加算、減算、乗算、除算」の四則演算を表しています。コードではこれら 4 つのメンバーの値を使用する必要はまったくなく、メンバー名だけで十分です。

TypeScript 5.0 以前、Enum にはバグがありました。つまり、Enum 型の変数です。任意の数値を割り当てることができます。

列挙型ブール値 {
  いいえ、
  はい
}

関数 foo(noYes:Bool) {
  // ...
}

foo(33); // TypeScript 5.0 より前ではエラーなし

上の例では、関数 foo のパラメーター noYes は Enum 型で、使用可能な値は 2 つだけです。ただし、TypeScript 5.0 より前では、関数 foo のパラメーターとして使用される値はコンパイル中にエラーを引き起こしませんでした。TypeScript 5.0 ではこの問題が修正されました。

また、Enum構造体はコンパイル後はオブジェクトであるため、同名の変数(オブジェクト、関数、クラスなどを含む)は存在できません。

列挙型の色 {
  赤、
  緑、
  青
}

const Color = 'red' // エラーレポート

上記の例では、Enum 構造体が変数と同じ名前を持っているため、エラーが発生します。

Enum 構造の大部分は、オブジェクトの「as const」アサーションによって置き換えることができます。

enum Foo {
  あ、
  B、
  C、
}

const バー = {
  答え: 0、
  B:1、
  子:2、
定数として;

if (x === Foo.A) {}
// と同等
if (x === Bar.A) {}

上記の例では、オブジェクト Baras const アサーションを使用しており、そのプロパティは変更不可能になっています。この場合、FooBar の動作は非常に似ており、前者は後者で完全に置き換えることができ、後者は JavaScript のネイティブ データ構造でもあります。

Enum メンバーの値

デフォルトでは、Enum メンバーに値を割り当てる必要はありません。システムは 0 から開始して 1 つずつ増加し、0、1、2... などの順序で各メンバーに値を割り当てます。

ただし、Enum メンバーに値を明示的に割り当てることもできます。

列挙型の色 {
  赤、
  緑、
  青
}

// と同等
列挙型の色 {
  赤 = 0、
  緑 = 1、
  青 = 2
}

上記の例では、Enum の各メンバーの値が明示的に割り当てられています。

メンバーの値は任意の数値にすることができますが、大きな整数 (Bigint) にすることはできません。

列挙型の色 {
  赤 = 90、
  緑 = 0.5、
  青 = 7n // エラーレポート
}

上の例では、Enum メンバーの値は 10 進数にすることができますが、Bigint にすることはできません。

メンバーの価値観が同じになることもあります。

列挙型の色 {
  赤 = 0、
  緑 = 0、
  青 = 0
}

最初のメンバーの値のみを設定すると、後続のメンバーの値はこの値から増加します。

列挙型の色 {
  赤 = 7、
  緑、// 8
  青 // 9
}

// または
列挙型の色 {
  赤、// 0
  緑 = 7、
  青 // 8
}

Enum メンバーの値は、式を使用して計算することもできます。

enum 権限 {
  ユーザー読み取り = 1 << 8、
  ユーザー書き込み = 1 << 7、
  ユーザー実行 = 1 << 6、
  GroupRead = 1 << 5、
  グループ書き込み = 1 << 4、
  グループ実行 = 1 << 3、
  すべて読み取り = 1 << 2、
  すべての書き込み = 1 << 1、
  すべて実行 = 1 << 0、
}

列挙型ブール値 {
  いいえ = 123、
  はい = Math.random()、
}

上記の例では、Enumメンバの値が計算式と等しいか、関数の戻り値と等しいのが正解です。

Enum メンバーの値は読み取り専用であり、再割り当てすることはできません。

列挙型の色 {
  赤、
  緑、
  青
}

Color.Red = 4; // エラーレポート

上記の例では、Enum メンバーに値を再割り当てするとエラーが発生します。

この点をより目立つようにするために、通常は enum キーワードの前に「const」修飾が追加され、それが定数であり再割り当てできないことを示します。

const enum Color {
  赤、
  緑、
  青
}

「const」を追加するもう 1 つの利点は、JavaScript コードにコンパイルした後、コード内の Enum メンバーが対応する値に置き換えられ、パフォーマンスが向上することです。

const enum Color {
  赤、
  緑、
  青
}

const x = Color.Red;
const y = Color.Green;
const z = Color.Blue;

//コンパイル後
const x = 0 /* Color.Red */;
const y = 1 /* Color.Green */;
const z = 2 /* Color.Blue */;

上記の例では、「const」キーワードが Enum 構造の前に追加されているため、コンパイルされた製品では対応するオブジェクトは生成されず、代わりに、すべての Enum メンバーが出現時に対応する定数に置き換えられます。

const キーワードを追加した後も実行時に Enum 構造体にアクセスできるようにしたい場合 (つまり、Enum はコンパイル後に引き続きオブジェクトに変換されます)、コンパイル中に preserveConstEnums コンパイル オプションをオンにする必要があります。 。

同じ名前の列挙型のマージ

同じ名前を持つ複数の Enum 構造は自動的にマージされます。

enum Foo {
  あ、
}

enum Foo {
  B = 1、
}

enum Foo {
  C = 2、
}

// と同等
enum Foo {
  あ、
  B = 1、
  C = 2
}

上の例では、Foo が 3 つの定義に分割されており、システムがそれらを自動的にマージします。

Enum 構造をマージする場合、そのうちの 1 つの最初のメンバーのみが初期値を省略できます。省略しない場合は、エラーが報告されます。

enum Foo {
  あ、
}

enum Foo {
  B, // エラーを報告する
}

上記の例では、Foo の 2 つの定義の最初のメンバーに初期値が設定されていないため、エラーが発生します。

同じ名前の列挙型をマージする場合、同じ名前のメンバーを持つことはできません。そうでない場合は、エラーが報告されます。

enum Foo {
  あ、
  B
}

enum Foo {
  B = 1, // エラー
  C
}

上記の例では、Foo の 2 つの定義に同じ名前のメンバー B が含まれているため、エラーが発生します。

同じ名前の列挙型をマージする場合のもう 1 つの制限は、すべての定義が const 列挙型または非 const 列挙型である必要があり、混合使用が許可されていないことです。

// 正しい
列挙型 E {
  あ、
}
列挙型 E {
  B = 1、
}

// 正しい
const enum E {
  あ、
}
const enum E {
  B = 1、
}

// エラーを報告する
列挙型 E {
  あ、
}
const enum E {
  B = 1、
}

同じ名前の Enum をマージする最大の用途は、外部で定義された Enum 構造を補足することです。

文字列列挙型

Enum メンバーの値を数値に設定するだけでなく、文字列に設定することもできます。つまり、Enum は関連する文字列のコレクションとして使用することもできます。

列挙型の方向 {
  上 = '上'、
  下 = '下'、
  左 = '左'、
  右 = 「右」、
}

上記の例では、「Direction」は文字列の列挙であり、各メンバーの値は文字列です。

文字列列挙のすべてのメンバー値は明示的に設定する必要があることに注意してください。設定されていない場合、メンバー値はデフォルトで数値になり、文字列メンバーの前に配置する必要があります。

enum Foo {
  あ、// 0
  B = 「こんにちは」、
  C // エラーを報告する
}

上記の例では、「A」の前に他のメンバーがないため、初期値を設定する必要はありません。デフォルトは「0」です。「C」の前に文字列メンバーがあるため、「C」になります。初期値が必要であり、値が割り当てられていない場合はエラーが報告されます。

Enum メンバーには、文字列と数値の混合値を割り当てることができます。

enum 列挙型 {
  1 = 「1」、
  2 = 「2」、
  3 = 3、
  4 = 4、
}

Enum メンバーには、数値および文字列 (シンボル値など) 以外の値は許可されません。

変数の型が文字列列挙型の場合、数値列挙型とは異なる文字列に割り当てることはできません。

enum MyEnum {
  1 = 「1」、
  2 = 「2」、
}

let s = MyEnum.One;
s = 'One' // エラーを報告します。

上記の例では、変数 s の型は MyEnum であり、これが文字列に代入されている場合はエラーが報告されます。

このため、関数のパラメータの型が文字列 Enum の場合、パラメータを渡すときに文字列を直接渡すことはできず、Enum メンバーを渡す必要があります。

enum MyEnum {
  1 = 「1」、
  2 = 「2」、
}

関数 f(arg:MyEnum) {
  return '引数は ' + 引数;
}

f('One') // エラーを報告する

上記の例では、パラメータのタイプは「MyEnum」であり、文字列が直接渡されるとエラーが報告されます。

したがって、string Enum は型として関数のパラメータを制限する機能を持っています。

前述したように、数値 Enum のメンバー値は重要ではないことがよくあります。ただし、場合によっては、開発者が有用な情報を保存するために Enum メンバー値を必要とする場合があるため、TypeScript は文字列 Enum を設計しました。

const enum MediaTypes {
  JSON = 'アプリケーション/json',
  XML = 'アプリケーション/xml'、
}

const url = 'ローカルホスト';

fetch(url, {
  ヘッダー: {
    受け入れる: MediaTypes.JSON、
  }、
}).then(応答 => {
  // ...
});

上記の例では、関数 fetch() のパラメーター オブジェクトの属性 Accept は、指定された一部の文字列のみを受け入れることができます。現時点では、文字列を Enum 構造体に配置し、メンバー値を通じてこれらの文字列を参照することが非常に適しています。

String Enum は共用体型に置き換えることができます。

関数移動(
  ここで:'上'|'下'|'左'|'右'
) {
  // ...
 }

上記の例では、関数パラメータ where は共用体型に属しており、その効果はそれを文字列 Enum として指定した場合と同じです。

文字列 Enum のメンバー値は式を使用して割り当てることができないことに注意してください。

enum MyEnum {
  A = 「1」、
  B = ['T', 'w', 'o'].join('') // エラーレポート
}

上記の例では、メンバー B の値が文字列式であるため、エラーが発生します。

キーオブ演算子

keyof 演算子は、Enum 構造体のすべてのメンバー名を取り出し、それらを共用体型として返すことができます。

enum MyEnum {
  A = 'a'、
  B = 'b'
}

// 'A'|'B'
type Foo = keyof typeof MyEnum;

上記の例では、keyof typeof MyEnumMyEnum のすべてのメンバー名を取得できるため、型 Foo は共用体型 'A'|'B' と同等です。

ここでの typeof は必須であり、それ以外の場合は keyof MyEnumkeyof string と同等であることに注意してください。

タイプ Foo = keyof MyEnum;
// Symbol.iterator の種類 | "charCodeAt" |

上記の例では、タイプ Foo は、タイプ string のすべてのネイティブ プロパティ名の共用体タイプと等しくなります。これは、MyEnum が文字列 Enum である場合、keyof MyEnumkeyof number と等価です。

これは、型としての Enum は本質的に number または string のバリアントであり、typeof MyEnumMyEnum を値として扱うため、最初にオブジェクト型に変換してから、 keyof 演算子を使用して、オブジェクトのすべてのプロパティ名を返します。

Enum のすべてのメンバー値を返したい場合は、「in」演算子を使用できます。

enum MyEnum {
  A = 'a'、
  B = 'b'
}

// { a: 任意、b: 任意 }
type Foo = { [MyEnum のキー]: 任意 };

上記の例では、属性インデックスを使用して MyEnum のすべてのメンバー値を取得できます。

逆マッピング

数値 Enum には逆マッピングがあります。つまり、メンバー名はメンバー値を通じて取得できます。

enum 平日 {
  月曜日 = 1、
  火曜日、
  水曜日、
  木曜日、
  金曜日、
  土曜日、
  日曜日
}

console.log(Weekdays[3]) // 水曜日

上記の例では、Enum メンバー「 Wednesday 」の値は 3 であるため、メンバー値 ' 3 ' から対応するメンバー名 ' Wednesday ' を取得できます。これを逆マッピングと呼びます。

これは、TypeScript が上記の Enum 構造を次の JavaScript コードにコンパイルするためです。

var 平日;
(関数(平日){
    Weekdays[Weekdays["Monday"] = 1] = "月曜日";
    平日[平日["火曜日"] = 2] = "火曜日";
    平日[平日["水曜日"] = 3] = "水曜日";
    平日[平日["木曜日"] = 4] = "木曜日";
    Weekdays[Weekdays["Friday"] = 5] = "金曜日";
    平日[平日["土曜日"] = 6] = "土曜日";
    平日[平日["日曜日"] = 7] = "日曜日";
})(平日 || (平日 = {}));

上記のコードでは、最初のメンバーを例として、2 セットの代入が実際に実行されます。

平日[
  平日["月曜日"] = 1
] = "月曜日";

上記のコードには 2 つの代入演算子 (=) があり、実際には次のコードと同等です。

平日["月曜日"] = 1;
平日[1] = "月曜日";

これは数値列挙型の場合にのみ発生し、文字列列挙型の逆マッピングはないことに注意してください。これは、String Enum が 1 セットの代入のみでコンパイルされるためです。

enum MyEnum {
  A = 'a'、
  B = 'b'
}

//コンパイル後
varMyEnum;
(関数 (MyEnum) {
    MyEnum["A"] = "a";
    MyEnum["B"] = "b";
})(MyEnum || (MyEnum = {}));

作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0