TypeScript リテラル型
リテラル型(Literal Types)は、TypeScript において汎用型ではなく特定の値を表す機能です。
これにより、変数の型を広範な string や number などの型ではなく、具体的な値に制限することができます。
これにより、より精密な型制御が可能になり、コードの型安全性が高まります。
SVG 図解:リテラル型
なぜリテラル型が必要なのか
TypeScript では、string や number などのデフォルトの型は広範すぎます。
時には、より精密な型制御が必要です。例えば、変数が特定の値のみを取れるようにする場合です。
リテラル型はまさにこのような問題を解決するために生まれました。
概念の説明:リテラル型は汎用型(string、number)の具体的な値です。例えば
"up"であるstringのサブタイプであり、代入できるのは特定の文字列のみです。
文字列リテラル型
文字列リテラル型は、変数の値を特定の文字列に制限します。
これは、変数を特定の固定値のみに制限する必要がある場合に非常に役立ちます。
例
// direction は4つの特定の値のいずれかでなければならない
var direction: "up" | "down" | "left" | "right";
// 正しい:リテラル型の値を代入
direction = "up";
// エラー:リストにない値を代入
// direction = "upup"; // コンパイルエラー!
console.log("方向: " + direction);
// 型エイリアスを使って再利用可能なリテラル型を作成
// 状態型を定義:3つの固定値のいずれかでなければならない
type Status = "pending" | "active" | "completed";
// 型エイリアスを使用
var currentStatus: Status = "active";
console.log("状態: " + currentStatus);
実行結果:
方向: up ステータス: active
適用場面:文字列リテラルは、列挙値、ステータスコード、設定オプションなど、特定の値に制限する必要がある場面でよく使用されます。
数値リテラル型
数値リテラル型は、変数の値を特定の数値に制限します。
これは、特定の数値(ステータスコード、エラーコードなど)を使用する必要がある場合に非常に役立ちます。
例
// code は3つの特定の値のいずれかでなければならない
var code: 200 | 404 | 500;
// 正しい:200 を代入
code = 200;
// エラー:リストにない値を代入
// code = 301; // コンパイルエラー!
console.log("ステータスコード: " + code);
// 数値リテラルを使って列挙型を模倣
// 1週間の日数を定義
type Weekday = 1 | 2 | 3 | 4 | 5 | 6 | 7;
// 1〜7の間の数値のみ代入できる
var today: Weekday = 1;
console.log("今日は曜日: " + today);
説明:数値リテラルは、特に少数の固定値だけが必要な場合に、単純な列挙型(enum)の代わりとして使用できます。
ブールリテラル型
ブールリテラル型は、変数の値を true または false に制限します。
実際、TypeScript の boolean 型は true | false のエイリアスです。
例
// isActive は true または false のみ
var isActive: true | false;
// true を代入
isActive = true;
// 実際、boolean は true | false のユニオン型
// したがって、この2つの書き方は等価
var flag: boolean = true;
console.log("アクティブか: " + isActive);
ヒント:boolean 自体で十分な場合もありますが、true と false の型を明確に区別する必要がある場合は、true または false を型として使用できます。
オブジェクトリテラル型
オブジェクトリテラル型はオブジェクトの構造を定義でき、readonly 修飾子を使ってプロパティを読み取り専用にできます。
これは、不変オブジェクトを作成する必要がある場合に非常に役立ちます。
例
// オブジェクトの構造とプロパティの型を指定
type Point = {
// 点の x 座標
x: number;
// 点の y 座標
y: number;
};
// オブジェクトリテラル型を使用
var p: Point = { x: 10, y: 20 };
console.log("点: " + JSON.stringify(p));
// 読み取り専用オブジェクト型を定義
// readonly 修飾子を使ってプロパティを読み取り専用にする
type ReadonlyPoint = {
// 読み取り専用の x 座標
readonly x: number;
// 読み取り専用の y 座標
readonly y: number;
};
// 読み取り専用オブジェクト型を使用
var rp: ReadonlyPoint = { x: 1, y: 2 };
// 読み取り専用プロパティを変更しようとするとエラーになる
// rp.x = 3; // コンパイルエラー:読み取り専用プロパティは変更できません
console.log("読み取り専用点: " + JSON.stringify(rp));
実行結果:
点: {"x":10,"y":20}
只读点: {"x":1,"y":2}
適用場面:読み取り専用オブジェクトは、設定オブジェクトや定数オブジェクトなど、変更されることを望まないデータを定義する際によく使用されます。
リテラル型と型推論
TypeScript は変数の宣言方法に応じて、リテラル型を自動的に推論します。
const で宣言された変数は、広範な型ではなく、具体的なリテラル型として推論されます。
例
// TypeScript は広範な型として推論する
var name = "Alice"; // 型: string(var は再代入できるため)
var age = 25; // 型: number
var enabled = true; // 型: boolean
console.log("名前: " + name + ", 年齢: " + age + ", 有効: " + enabled);
// as const を使って深い読み取り専用リテラルを作成
// 配列は読み取り専用タプルになり、値はリテラル型
var colors = ["red", "green", "blue"] as const;
// colors の型は次のようになる:
// readonly ["red", "green", "blue"]
// 配列要素にアクセス
console.log("色: " + colors[0]);
// 変更しようとするとエラーになる
// colors
説明:
as const型を最も具体的なリテラル型として推論し、readonly 修飾子を追加します。
テンプレートリテラル型
テンプレートリテラル型は、JavaScript のテンプレート文字列の構文を使用して新しい型を作成します。
これにより、文字列型を動的に生成できます。
例
// `on${string}` は "on" で始まる任意の文字列を表す
type EventName = `on${string}`;
// テンプレートリテラル型を使ってハンドラー名を定義
// Capitalize は文字列の先頭文字を大文字にする
type Handler = `handle${Capitalize<string>}`;
// テンプレートリテラル型を使用
var event: EventName = "onClick";
var handler: Handler = "handleSubmit";
console.log("イベント: " + event);
console.log("ハンドラー: " + handler);
// 错误:不符合模板格式
// var e: EventName = "click"; // コンパイルエラー:"on" で始まっていません
运行结果:
事件: onClick 处理器: handleSubmit
組み込みユーティリティ型:テンプレートリテラル型は、Uppercase、Lowercase、Capitalize、Uncapitalize などの組み込みユーティリティ型と組み合わせて使用できます。
実践応用:Redux Action
リテラル型は実際の開発において広く応用されています。
以下では、リテラル型を使用してReduxスタイルのアクションを実装する方法を示します。
例
// ユニオン型を使用して異なるタイプのActionを定義する
type Action =
// インクリメントタイプの Action、数値型の payload を含む
| { type: "increment"; payload: number }
// デクリメントタイプの Action、数値型の payload を含む
| { type: "decrement"; payload: number }
// リセット型の Action、ペイロードなし
| { type: "reset" };
// action を使用する reducer 関数
function reducer(action: Action): void {
// TypeScript は action.type の値に基づいて action の具体的な型を自動的に推論します。
switch (action.type) {
case "increment":
// この分岐では、action は { type: "increment"; payload: number } と推論されます。
console.log("增加: " + action.payload);
break;
case "decrement":
// この分岐では、action は { type: "decrement"; payload: number } と推論されます。
console.log("减少: " + action.payload);
break;
case "reset":
// この分岐では、action は { type: "reset" } と推論されます。
console.log("重置");
break;
}
}
// 異なるタイプの Action をディスパッチする
reducer({ type: "increment", payload: 5 });
reducer({ type: "reset" });
运行结果:
增加: 5 重置
判別可能なユニオン:このパターンは「判別可能なユニオン」(Discriminated Union)と呼ばれ、TypeScript で複数の関連する型を扱うためのベストプラクティスです。
注意事項
- 类型收窄:switchやifで判定する際、TypeScriptは自動的にリテラル型を絞り込みます。
- 类型别名:一般的なリテラル型には、typeエイリアスを使用して別名を作成することをお勧めします。
- const 推断:constで宣言された変数は自動的にリテラル型として推論されます。
- as const:深い読み取り専用が必要な場合はas constを使用します。
最佳实践:変数を特定の値のみに制限する必要がある場合は、列挙型ではなくリテラル型を優先的に使用します。
まとめ
リテラル型は、TypeScriptが精密な型制御を実現するための重要な機能です。
- 文字列リテラル:特定の文字列に制限する、例:
"up" | "down" - 数値リテラル:特定の数値に制限する、例:
1 | 2 | 3 - ブールリテラル:true または false に制限
- オブジェクトリテラル:オブジェクト構造を定義する際は、readonlyを使用できます。
- as const:深い読み取り専用のリテラル型を作成する
- テンプレートリテラル:テンプレート文字列を使用して型を動的に生成する
其他扩展进阶:リテラル型と判別可能なユニオン型パターンを組み合わせることで、強力な型安全性を実現できます。