はじめに
G's(旧G’s Academy)東京LAB18期卒のエンジニアをしております
H_Kagami_Gsと申します。
今回はG’s EXPANSION PROGRAMというアドオン講座で
TypeScriptの講座を受講しており、
課題でnever型について調べるにあたり、
理解を深めたく記事を作成しました。
自分は恥ずかしながら、
今回のTypeScriptを学んでいると、neverという型に出会うことがあります。
「voidとは違うの?」「いつ使うの?」と疑問に思う方も多いのではないでしょうか。
この記事では、Never型とは何かを初学者の方にもわかりやすく解説します。
Never型を一言でいうと
「絶対に値が存在しない」ことを表す型です。
どんな時に使われるか
1. ありえない状態を表現する(網羅性チェック)
これが実務で最も便利な使い方です。
type Animal = "dog" | "cat" | "bird";
function getSound(animal: Animal): string {
switch (animal) {
case "dog":
return "ワン";
case "cat":
return "ニャー";
case "bird":
return "ピヨ";
default:
// ここに到達することは「ありえない」
const _exhaustiveCheck: never = animal;
return _exhaustiveCheck;
}
}
すべてのケースを網羅しているので、defaultに到達することはありえません。そのため、animalをnever型の変数に代入できます。
網羅性チェックの威力
もし後から Animal に "fish" を追加したとします。
type Animal = "dog" | "cat" | "bird" | "fish"; // fishを追加
このとき、getSound関数にcase "fish"を書き忘れると、コンパイルエラーが発生します。
Type 'string' is not assignable to type 'never'.
これにより、case文の書き忘れをコンパイル時に検出できます。これが網羅性チェック(Exhaustiveness Check)の力です。
voidとの違い
よく混同されるので整理しておきましょう。
| 型 | 意味 | 例 |
|---|---|---|
void |
「何も返さない」(undefinedを返す) | console.log() |
never |
「絶対に戻ってこない」 | throw new Error() |
// void:関数は正常に終了する(undefinedを返す)
function logMessage(msg: string): void {
console.log(msg);
}
初学者向けのイメージ
- void = 「空っぽの箱を返す」
- never = 「箱すら返ってこない(届かない)」
実務でよく見るパターン
APIレスポンスの型を厳密にチェックする例です。
type ApiResponse =
| { status: "success"; data: string }
| { status: "error"; message: string };
function handleResponse(res: ApiResponse): void {
switch (res.status) {
case "success":
console.log(res.data);
break;
case "error":
console.log(res.message);
break;
default:
// 将来statusの種類が増えた時に
// ここでコンパイルエラーが出て気づける
const _: never = res;
}
}
将来的にstatusの種類が増えた場合、case文を追加し忘れるとコンパイルエラーで気づけます。
補足:assertNever関数パターン
網羅性チェックを再利用可能にするため、ヘルパー関数を定義するパターンもよく使われます。
function assertNever(value: never): never {
throw new Error(`Unexpected value: ${value}`);
}
type Status = "pending" | "approved" | "rejected";
function getStatusLabel(status: Status): string {
switch (status) {
case "pending":
return "保留中";
case "approved":
return "承認済み";
case "rejected":
return "却下";
default:
return assertNever(status);
}
}
このassertNever関数を使うことで、網羅性チェックのコードを統一できます。
まとめ
| ポイント | 内容 |
|---|---|
| Never型とは | 「絶対に値が存在しない」を表す型 |
| 主な用途 | switch文の網羅性チェック |
| voidとの違い | voidは「空を返す」、neverは「戻ってこない」 |
最初は「なんでこんな型が必要なの?」と思うかもしれませんが、
TypeScriptを使い込むほどその価値がわかってきます。
特に網羅性チェックは、Union型の追加忘れを防ぐ実践的なテクニックです。