TypeScript クラス内列挙型解説
基本的な構文
class MyClass {
enum MyEnum {
Value1,
Value2,
Value3
}
}
アクセス方法
クラス内の列挙型にアクセスするには、クラス名と列挙型名をドットで繋いで使用します。
let value1 = MyClass.MyEnum.Value1;
定義ファイルでの使用
TypeScript 定義ファイル(.d.ts
ファイル)では、クラス内の列挙型を次のように定義します。
declare class MyClass {
enum MyEnum {
Value1,
Value2,
Value3
}
}
注意
- 定義ファイルで列挙型を定義する場合、そのクラスが実際に実装されているかどうかは関係ありません。
- 列挙型のメンバーは、デフォルトでは数値でインデックス付けされます。数値以外の値を割り当てることもできます。
- TypeScript の列挙型は、JavaScript にコンパイルされた際には、ただのオブジェクトになります。そのため、ランタイムでの型チェックは行われません。
例
// 定義ファイル (MyClass.d.ts)
declare class MyClass {
enum Color {
Red,
Green,
Blue
}
}
// 実装ファイル (MyClass.ts)
class MyClass {
enum Color {
Red = 1,
Green = 2,
Blue = 3
}
}
この例では、MyClass
クラス内に Color
という列挙型を定義しています。この列挙型は、Red
、Green
、Blue
の 3 つの値を持ちます。
TypeScript クラス内列挙型解説とコード例
クラス内列挙型とは?
メリット
- コードの再利用
クラス内で定義された列挙型は、そのクラスのメソッド内で再利用できます。 - 型安全
列挙型の値しか代入できないため、誤った値の代入を防ぎ、バグを減らすことができます。 - コードの可読性向上
定数を意味のある名前で定義することで、コードの意図を明確にできます。
class MyClass {
enum MyEnum {
Value1,
Value2,
Value3
}
// MyEnum を使用するメソッド
myMethod(value: MyEnum) {
// ...
}
}
コード例解説
例1: 色を表す列挙型
class Shape {
enum Color {
Red,
Green,
Blue
}
draw(color: Color) {
// 色に応じて図形を描く処理
console.log(`Drawing a shape in ${Color[color]} color.`);
}
}
let shape = new Shape();
shape.draw(Shape.Color.Red); // 出力: Drawing a shape in Red color.
Shape.Color.Red
のように、クラス名と列挙型名をドットで繋いでアクセスする。draw
メソッドでColor
型のパラメータを受け取り、色に応じた処理を行う。Shape
クラス内にColor
という列挙型を定義。
class Order {
enum Status {
Pending,
Processing,
Completed,
Canceled
}
status: Status;
// ...
}
status
プロパティにStatus
型の値を割り当てる。Order
クラス内にStatus
という列挙型を定義。
例3: 定義ファイルでの定義
// 定義ファイル (MyClass.d.ts)
declare class MyClass {
enum MyEnum {
Value1,
Value2,
Value3
}
}
- 実装ファイルで具体的な実装を行う。
- 定義ファイルでは、クラスと列挙型の構造を定義する。
さらに詳しく
- JavaScriptとの関係
JavaScript には列挙型はありませんが、TypeScript の列挙型は JavaScript のオブジェクトにコンパイルされます。 - 継承
列挙型は継承できません。 - const enum
コンパイル時に定数に置き換えられる列挙型。 - 数値以外の値
文字列やオブジェクトを値として割り当てることもできます。
TypeScript のクラス内列挙型は、定数を管理し、コードの可読性と保守性を高めるための強力なツールです。特に、状態を表す値や、限られた選択肢しかない値を扱う場合に有効です。
ポイント
- 定義ファイルで定義することで、他のファイルから利用できる。
- 型安全で、誤った値の代入を防ぐことができる。
- クラス内で定義することで、そのクラスに固有の定数を管理できる。
活用例
- 設定値
- エラーコード
- イベントの種類
- 状態管理 (e.g., 注文状態、ユーザー状態)
キーワード
TypeScript, クラス内列挙型, enum, 定義ファイル, 型安全, コードの可読性
const assertion
- デメリット
- 型の安全性は列挙型に比べて低い。
- 定数の管理が散らばる可能性がある。
- メリット
- シンプルで柔軟性が高い。
- 列挙型のように厳密な構造を必要としない場合に適している。
- 特徴
- 任意の値を定数として扱う。
- 型アサーションを用いて、その値の型を制限する。
class MyClass {
private readonly COLOR_RED = 'red' as const;
private readonly COLOR_GREEN = 'green' as const;
// ...
}
型別ユニオン
- デメリット
- 型の定義が複雑になる可能性がある。
- メリット
- 型の安全性が高い。
- より柔軟な表現が可能。
- 特徴
- 複数の型を一つの型として扱う。
- 列挙型の値を文字列や数値で表現する。
class MyClass {
type Color = 'red' | 'green' | 'blue';
private color: Color;
// ...
}
文字列リテラル型
- デメリット
- 柔軟性がやや低い。
- メリット
- 可読性も良い。
- 特徴
- 特定の文字列値のみを許容する型。
- 型別ユニオンと似ているが、より簡潔な表現が可能。
class MyClass {
private color: 'red' | 'green' | 'blue';
// ...
}
マッピング型
- デメリット
- 初期学習コストが高い。
- メリット
- 複雑な型の変換に役立つ。
- 特徴
- 既存の型から新しい型を生成する。
- オブジェクト型のキーと値の関係を定義する。
type ColorMap = {
RED: 'red';
GREEN: 'green';
BLUE: 'blue';
};
class MyClass {
private color: keyof ColorMap;
// ...
}
定数インターフェース
- 特徴
- インターフェースを使って定数を定義する。
- 型の安全性と可読性を両立できる。
interface Color {
readonly RED: 'red';
readonly GREEN: 'green';
readonly BLUE: 'blue';
}
class MyClass {
private color: Color['RED'];
// ...
}
どの方法を選ぶべきか?
- 拡張性
マッピング型
や定数インターフェース
は拡張性が高い。 - 可読性
列挙型
や定数インターフェース
は可読性が高いが、冗長になる可能性がある。 - 型安全性
型別ユニオン
やマッピング型
は型安全性が高いが、複雑な場合がある。 - シンプルさ
const assertion
や文字列リテラル型
はシンプルだが、型安全性は低い。
選ぶ際のポイント
- 拡張性
将来的に定数を追加する可能性がある場合はマッピング型
や定数インターフェース
を検討。 - 可読性
コードの可読性を重視する場合は列挙型
や定数インターフェース
を検討。 - 型安全性
高い型安全性が必要であれば型別ユニオン
やマッピング型
を検討。 - 定数の数
少数の定数であればconst assertion
や文字列リテラル型
で十分。
クラス内列挙型以外の選択肢は、それぞれ特徴やメリット・デメリットがあります。プロジェクトの規模や要件に合わせて、最適な方法を選択することが重要です。
- TypeScript のバージョンによっては、より新しい機能や改善が加わっている可能性があります。
- 上記以外にも、JavaScript の
Object.freeze
を利用する方法や、サードパーティライブラリを利用する方法など、様々な選択肢があります。
typescript definition