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 の lru リンク リストの簡単な分析

1. 従来のLRUリンクリストについて簡単に説明するLRU:最も最近使われなかったものLRU リンク...

tomcat デプロイメント プロジェクトの実装と IDEA との統合

目次Tomcat でプロジェクトを展開する 3 つの方法プロジェクトをwebappsディレクトリに直...

Docker を使用して静的 Web サイト アプリケーションを作成する (複数の方法)

静的ウェブサイトをホストできるサーバーは数多くあります。この記事では、nginx、apache、to...

シンプルな加算計算機の JavaScript 実装

この記事では、参考までに、加算計算機を実装するためのJavaScriptの具体的なコードを紹介します...

Springboot プロジェクトに動的にパラメータを渡すための Docker の実装方法

背景最近、Docker 初心者の友人から、毎回プロジェクト構成ファイルにハードコーディングしてサービ...

Vueのカスタムイベントコンテンツ配信の詳細な説明

1. これは理解するのが少し複雑なので、原理を注意深く読んで自分で入力していただければ幸いです。 &...

MySQLは1つのテーブルからデータをクエリし、それを別のテーブルに挿入する実装方法

MySQLは1つのテーブルからデータをクエリし、それを別のテーブルに挿入する実装方法ウェブサイト開発...

Dockerコンテナデータボリュームの原理と使用法の分析

コンテナデータボリュームとはデータがコンテナ内にある場合、コンテナを削除するとデータは失われます。例...

MySQL でタイムゾーンを表示および変更する方法

今日、プログラムが間違った時刻を挿入し、フィールドがデフォルト値 CURRENT_TIMESTAMP...

Axios はリクエストをキャンセルし、重複リクエストを回避します

目次起源現状リクエストをキャンセル cancelTokenリクエスト方法の変更重複したリクエストを避...

Mac OS 10.11 での MySQL 5.7.12 のインストールと設定のチュートリアル

Mac OS 10.11 に MySQL をインストールして設定する方法を、主に写真を使って手順を簡...

WindowsシステムでPhPStudy MySQLの起動に失敗する問題を解決する

エラーを報告するApache\Nginx サービスは正常に起動しましたが、MySQL は起動に失敗し...

mysqlとnavicat間の接続を確立する際の1251エラーを解決する

コンピュータを再インストールし、最新バージョンのMySQLデータベースをインストールしました。その結...

25 個の CSS フレームワーク、ツール、ソフトウェア、テンプレートを共有

スプライトカウダウンロード CSS リントダウンロード プレフィックスダウンロード 1140px C...

MySQL の列から行への変換、フィールドの結合方法 (必読)

データシート:列から行へ: max(case when then) を使用max---集計関数は最大...