📚
TypeScriptのassertNeverで型安全性を極める:switch文の完全ガイド
はじめに
TypeScriptを使う上で、型安全性は常に重要なトピックです。特に、列挙型(enum)やユニオン型を扱うswitch文では、すべてのケースを漏れなく処理することが求められます。この記事では、assertNever
関数を使って型安全性を高める方法を、switch文を中心に詳しく解説します。
assertNeverとは
assertNever
は、コンパイル時に到達してはいけないコードパスを明示的に示すための関数です。基本的な実装は以下のとおりです。
function assertNever(x: never): never {
throw new Error("Unexpected object: " + x);
}
この関数は、never
型の引数を受け取り、常に例外をスローします。TypeScriptの型システムにおいて、never
型は「決して発生しない」値の型を表します。
switch文での使用例
交通信号の色を表す列挙型を例に、assertNever
の使用方法を見ていきましょう。
enum TrafficLight {
Red,
Yellow,
Green
}
パターン1: assertNeverを使用する場合
function getAction(light: TrafficLight): string {
switch (light) {
case TrafficLight.Red:
return "Stop";
case TrafficLight.Yellow:
return "Caution";
case TrafficLight.Green:
return "Go";
default:
return assertNever(light);
}
}
このパターンでは、すべてのケースが処理されていることが保証されます。新しい値がTrafficLight
に追加された場合、コンパイラがエラーを報告します。
パターン2: defaultを書く場合
function getAction(light: TrafficLight): string {
switch (light) {
case TrafficLight.Red:
return "Stop";
case TrafficLight.Yellow:
return "Caution";
case TrafficLight.Green:
return "Go";
default:
return "Unknown action";
}
}
このパターンでは、コンパイルエラーは発生しませんが、新しい値がTrafficLight
に追加された際に気づきにくくなります。
パターン3: defaultを書かない場合
function getAction(light: TrafficLight): string {
switch (light) {
case TrafficLight.Red:
return "Stop";
case TrafficLight.Yellow:
return "Caution";
case TrafficLight.Green:
return "Go";
}
}
このパターンでは、TypeScriptの設定によって動作が異なります:
-
--strictNullChecks
が有効な場合:コンパイラは、関数がundefined
を返す可能性があることを警告します。 -
--strictNullChecks
が無効な場合:警告なしでundefined
が返される可能性があります。
各パターンの比較
特性 | assertNever | defaultあり | defaultなし |
---|---|---|---|
型安全性 | 高 | 低 | 中(設定依存) |
コード網羅性 | 完全保証 | 保証なし | 部分的(設定依存) |
保守性 | 高 | 低 | 中(設定依存) |
assertNeverの利点
- 網羅性の保証: すべてのケースが処理されていることを保証します。
- リファクタリングの安全性: 型の定義変更時に関連箇所の更新漏れを防ぎます。
- ランタイムの安全性: 想定外の値に対して明示的なエラーをスローします。
注意点
-
assertNever
は主にコンパイル時のチェックのために使用されます。 - 実行時に
assertNever
関数が呼び出されることは、通常はバグを意味します。
まとめ
assertNever
を使用することで、TypeScriptの型システムをより活用し、コードの安全性と保守性を高めることができます。
Discussion