TypeScript の Enum が問題となる理由

TypeScript の Enum が問題となる理由

TypeScript は、クラス (現在は JavaScript の一部)、インターフェース、ジェネリック、ユニオン型など、静的にコンパイルされた言語の多くの機能を導入します。

しかし、今日は詳細に議論する必要がある型があります。それは enum です。

多くの静的言語では、列挙は非常に一般的な言語機能です。たとえば、C、C#、Java、Swift などです。列挙型は、コード内で使用できる定数のセットです。

TypeScript を使用して、曜日を表す新しい列挙型を作成します。

列挙型曜日 {
  日曜日、
  月曜日、
  火曜日、
  水曜日、
  木曜日、
  金曜日、
  土曜日
};

この列挙は、enum キーワードとそれに続く DayOfWeek 名を使用して宣言されます。次に、列挙で使用できる定数を定義します。

ここで、この列挙型のパラメータを受け入れて、渡されたパラメータが週末であるかどうかを判断するメソッドを定義します。

関数 isItTheWeekend(day: DayOfWeek) {
  スイッチ(日){
    DayOfWeek.Sundayの場合:
    DayOfWeek.Saturdayの場合:
      true を返します。
 
    デフォルト:
      false を返します。
  }
}

最後に、これを使用できます。

console.log(isItTheWeekend(DayOfWeek.Monday)); // ログ: false

これは、プログラム内の魔法の文字列を排除するのに非常に便利な方法です。

しかし、物事は私たちが考えるほど単純ではありません。次のコード呼び出しは、TypeScript のコンパイル後に何を取得しますか?

console.log(isItTheWeekend(2)); // これは有効ですか?

その結果を知れば、あなたはショックを受けるでしょう。このような呼び出しは TypeScript の規則に準拠しており、コンパイラは正常にコンパイルします。

どうしたの?

上記の状況から、TypeScript のバグを発見したと思われるかもしれません。実際、TypeScript はこのように設計されています。

ここで新しい数値列挙を作成し、TypeScript プレイグラウンドでコンパイルされた結果を確認できます。

曜日を指定します。
(関数 (曜日) {
    DayOfWeek[DayOfWeek["日曜日"] = 0] = "日曜日";
    DayOfWeek[DayOfWeek["Monday"] = 1] = "月曜日";
    DayOfWeek[DayOfWeek["火曜日"] = 2] = "火曜日";
    DayOfWeek[DayOfWeek["水曜日"] = 3] = "水曜日";
    DayOfWeek[DayOfWeek["木曜日"] = 4] = "木曜日";
    DayOfWeek[DayOfWeek["金曜日"] = 5] = "金曜日";
    DayOfWeek[DayOfWeek["土曜日"] = 6] = "土曜日";
})(曜日 || (曜日 = {}));

結果は次のとおりです。

実際、列挙は JavaScript オブジェクトです。

このオブジェクトのプロパティは、定義した列挙定数に従って生成され、対応する数値は定義された順序に従って生成されます (順序としては、日曜日は 0、土曜日は 6)。このオブジェクトには、キーとして数値を持ち、値として対応する定数文字列を持つプロパティもあります。

したがって、上記のメソッドに数値を渡すことができ、その数値は対応する列挙値にマッピングされます。列挙型は数値定数と文字列定数の両方です。

いつ使うか

メソッドが列挙型のパラメータを受け取った場合でも、任意の数がコンパイルされます。このような結果は、TypeScript によって構築された型安全性システムを明らかに破壊します。これはいつ使用できますか?

JSON 文字列を返すサービスがあり、特定のプロパティが列挙型になるようにこの文字列をモデル化したいとします。

データベースに保存するのは数値です。これは、TypeScript 列挙型を定義することで簡単に解決できます。

定数日: DayOfWeek = 3;

代入中に実行されるこの明示的な型変換により、数値が列挙体の対応する定数に変換されます。つまり、コード内でこの列挙体を使用すると、コードが読みやすくなります。

列挙の数を制御する

列挙体のメンバーに対応する番号は、列挙定数によって定義された順序に従って生成されます。この数値を制御できますか?はい、できます。

列挙型ファイル状態{
  読み取り = 1、
  書く = 2
}

ファイルの可能な状態を記述する単なる列挙です。

読み取り状態または書き込み状態のいずれかにすることができ、列挙値を明示的に定義します。明示的に定義されているため、どの値が妥当であるかが明確になりました。

ビット値

しかし、ビット値という非常に便利なケースがもう 1 つあります。

FileState 列挙をもう一度見て、新しい列挙値 ReadWrite を追加してみましょう。

列挙型ファイル状態{
  読み取り = 1、
  書き込み = 2、
  読み取り書き込み = 3
}

次に、このタイプのパラメータを受け入れるメソッドがあるとします。

const file = await getFile("/path/to/file", FileState.Read | FileState.Write);

FileState で | 演算子を使用しました。この方法では、ビット演算を使用して新しい列挙値を取得できます。この例では、ReadWrite の値は 3 です。

実際、もっと明確に書くこともできます。

列挙型ファイル状態{
  読み取り = 1、
  書き込み = 2、
  ReadWrite = 読み取り | 書き込み
}

この ReadWrite の値はハードコードされているのではなく、ビット演算によって取得されます。

ただし、このような列挙型を使用する場合は注意してください。

次の列挙:

列挙型Foo{
  A = 1、
  B = 2、
  C = 3、
  D = 4、
  E = 5
}

E (または 5) を取得したい場合、ビット演算 (Foo.A | Foo.D または Foo.B | Foo.C) で実行できますか?

したがって、列挙値を使用してビット演算を実行する場合は、値を取得する方法を知っておく必要があります。

コントロールインデックス

通常、各列挙値にはデフォルトの数値があります。必要に応じて、これらの列挙値に明示的に値を割り当てることもできます。さらに、列挙体の特定の部分に値を割り当てることもできます。

列挙型曜日 {
  日曜日、
  月曜日、
  火曜日、
  水曜日 = 10、
  木曜日、
  金曜日、
  土曜日
}

最初のいくつかの値は、日曜日から火曜日まで 0 から 2 までの位置によって割り当てられます。その後、水曜日に新しい値が割り当てられ、それ以降は各値が 1 ずつ増加します。これにより問題が発生する可能性があります。

列挙型曜日 {
  日曜日、
  月曜日、
  火曜日、
  水曜日 = 10、
  木曜日 = 2、
  金曜日、
  土曜日
}

火曜日には値 2 が割り当てられます。生成された JavaScript はどのようになるでしょうか?

曜日を指定します。
(関数 (曜日) {
    DayOfWeek[DayOfWeek["日曜日"] = 0] = "日曜日";
    DayOfWeek[DayOfWeek["Monday"] = 1] = "月曜日";
    DayOfWeek[DayOfWeek["火曜日"] = 2] = "火曜日";
    DayOfWeek[DayOfWeek["水曜日"] = 10] = "水曜日";
    DayOfWeek[DayOfWeek["木曜日"] = 2] = "木曜日";
    DayOfWeek[DayOfWeek["金曜日"] = 3] = "金曜日";
    DayOfWeek[DayOfWeek["土曜日"] = 4] = "土曜日";
})(曜日 || (曜日 = {}));

火曜日と木曜日は両方とも値が 2 のようです。

そのため、設定した値を表示する必要があります。

非数値列挙

これまでは数値列挙についてのみ説明してきましたが、列挙値は必ずしも数値である必要はありません。任意の定数または計算値にすることもできます。

列挙型曜日 {
  日曜日 = 「太陽」、
  月曜日 = "Mon"、
  火曜日 = 「火曜日」、
  水曜日 = "Wed",
  木曜日 = "木"、
  金曜日 = "Fri",
  土曜日 = "Sat"
}

現在、isItTheWeekend メソッドに数値パラメータを渡すことはできません。この列挙はもはや数値列挙ではありません。ただし、列挙型ではどの値が適切であるかがわかっているため、任意の文字列を渡すことはできません。

これにより、別の問題も発生します。

定数日: DayOfWeek = "月";

これはうまくいきません。

文字列を列挙型に直接割り当てることはできませんが、明示的な型変換が必要です。

const day = "Mon" を DayOfWeek として指定します。
他の値を割り当てることはできますか?実際、列挙型には多くの種類の値があります。

enum 混乱する {
  あ、
  B = 1、
  C = 1 << 8、
  D = 1 + 2、
  E = "Hello World".長さ
}

この例の列挙値はすべて数値です。ただし、これらの数値は直接割り当てることも、計算された値や文字列の長さプロパティに割り当てることもできます。すべて定数の場合、さまざまなタイプの値を取ることができます。

列挙型MoreConfusion{
  あ、
  B = 2、
  C = "C"
}

この場合、列挙の背後にあるデータがどのように機能するかを理解するのは難しいです。したがって、このような列挙は使用しない方がよいでしょう。

結論は

TypeScript の列挙型は JavaScript を補完する優れたものであり、適切に使用すると非常に便利です。コード内に存在するマジック値の文字列と数字をクリーンアップするのに役立ちます。そして型安全です。

TypeScript Enum に問題がある理由についてはこれで終わりです。TypeScript Enum の詳細については、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • React+TypeScriptプロジェクト構築事例解説
  • TypeScript 関数の定義と使用例のチュートリアル
  • 1つの記事でTypeScriptのデータ型について学ぶ
  • Typescript の as、疑問符、感嘆符の詳細な説明
  • webpackを使用してTypeScriptコードをパッケージ化およびコンパイルする方法を教えます
  • Typescript での infer キーワードの使用に関する詳細な理解
  • TypeScript をインストール、使用、自動コンパイルする方法に関するチュートリアル
  • TypeScript インターフェース定義ケースチュートリアル

<<:  CentOS サーバーのセキュリティ構成戦略

>>:  シェルスクリプトを使用して Docker サービスを一括で開始および停止する

推薦する

MySQLデータストレージプロセスパラメータの詳細な例

MySQL ストアド プロシージャ パラメータには、in、out、inout の 3 種類があります...

JS が WeChat の「クソ爆弾」機能を実装

みなさんこんにちは、Qiufengです。最近、WeChatは新しい機能をリリースしました(WeCha...

JS でオブジェクト プロパティを簡単にトラバースするいくつかの方法

目次1. 自己列挙可能なプロパティ2. Object.values()はプロパティ値を返します3. ...

長いデータを HTML で表示するときに処理する方法

HTML で長いデータを表示する場合、マウスをその上に移動するとデータを切り捨てて完全なデータを表示...

MySQL データベースの Binlog 使用法の概要 (必読)

MySQL データベースにとって binlog バイナリ ログがどれほど重要であるかについては詳し...

JS オブジェクト コンストラクター Object.freeze

目次概要例1) オブジェクトをフリーズする2) 配列をフリーズする3) 浅い凍結4) ディープフリー...

Centos8 システムの VMware インストール チュートリアル図 (中国語グラフィカル モード)

目次1. ソフトウェアとシステムイメージ2. 仮想マシンを作成する3. CentOS8をインストール...

GTK ツリービューの原理と使用法の分析

GtkTreeView コンポーネントは、美しい通常のリストやツリーのようなリストを作成できる高度な...

Mysqlデータベースの文字化けに対処する方法

MySQL では、データベースの文字化けは一般的に文字セットを設定することで修正できますが、文字化け...

vscode で Prettier Code プラグインを使用する詳細なチュートリアル

なぜprettierを使うのですか?大企業では、フロントエンド開発コードに独自のコード標準がある場合...

MySQL でサーバーのインストールを開始できない場合の解決策について簡単に説明します。

コンピュータに初めて MySQL をインストールする場合、通常このエラー メッセージは表示されません...

JSは文字列内の指定された文字列のn番目の出現位置を取得します

文字の位置を取得するための同様の方法について学習します。 charAt() 文字列内の指定された位置...

LinuxでDHCPサーバーを構築する方法

目次1. 基礎知識: 2. DHCPサーバーの設定: 1. サーバーのIPを確認する2. DHCP ...