TypeScript PR

【TypeScript】never型ってどこで使うの?特徴と使い所

【TypeScript】never型ってどこで使うの?特徴と使い所
記事内に商品プロモーションを含む場合があります

こんにちは!
今日はTypeScriptのnever型について詳しくお話ししましょう。

TypeScriptはJavaScriptに型付けを加えた言語で、コードの安全性と可読性を向上させるために利用されていますね。
その中でも、never型は少し特殊な役割を持っています。

このnever型、名前を聞いただけでは「何だか使い道がなさそう」と思うかもしれません。
でも実際には、never型はコードの予期しない部分を明示的に示すために重要な役割を果たします。
エラー処理や無限ループ、型ガードなど、さまざまな場面で役立つことを知っておくと便利です。

この記事では、never型がどのように使われるか、具体的な例を交えて詳しく解説していきます。

never型とは

まず、never型とは何かを理解しましょう。
never型は、TypeScriptで非常に特殊な型の一つ。
具体的には、「決して値を返さない」ことを示す型です。

例えば、関数が常に例外をスローするか、無限ループに入る場合、その関数の戻り値の型はneverとなります。
なぜなら、その関数は正常に終了して値を返すことがないからです。

以下の例を見てみましょう。


function throwError(message: string): never {
  throw new Error(message);
}

この関数throwErrorは、常に例外をスローします。
そのため、戻り値の型はneverです。
このように、never型は「決して値を返さない」ことを示すために使われます。

また、never型は型の絞り込み(型ガード)にも役立ちます。
型ガードの結果として到達不可能なコードを表現することが可能です。
そうすることで、コンパイラはコードの安全性を確保しやすくなるでしょう。

never型の特徴

never型の特徴について、さらに詳しく見ていきましょう。
never型は他の型と異なり、非常にユニークな性質を持っています。

まず、never型は「どの型とも互換性がない」ことが挙げられます。
つまり、never型を持つ変数には、どんな値も代入することができません。
これは、never型が「決して値を持たない」ことを示しているためです。

例えば、以下のようなコードを考えてみましょう。


// エラー: 型 'number' を型 'never' に割り当てることはできません。ts(2322)
const a: never = 5;

このように、never型の変数に値を割り当てることはできません。

次に、never型は「どの型にでも割り当てることができる」点です。
これもnever型の重要な特徴です。
つまり、never型はサブタイプとして扱われるため、どの型の変数にもnever型を代入することができます。


function infiniteLoop(): never {
  while (true) {}
}

// OK: never型はstring型に割り当て可能
const b: string = infiniteLoop();

このコードでは、infiniteLoop関数がnever型を返すため、その結果をstring型の変数bに代入することが可能です。

never型が使われる場面

never型は、プログラムの中で特定の状況を示すために使用されます。
ここでは、具体的にどのような場面でnever型が役立つのかを見ていきましょう。

例外処理での使用

never型は、例外処理の場面でよく使われます。
例えば、関数が例外をスローする場合、その関数は正常に終了せず、値を返すこともありません。
このため、関数の戻り値の型としてneverが使われます。


function throwError(message: string): never {
	throw new Error(message);
}

このthrowError関数は常に例外をスローするため、戻り値の型はneverです。

無限ループでの使用

無限ループも、never型が使われる典型的な場面です。
無限ループに入る関数は、決して正常に終了しないため、戻り値の型はneverとなります。


function infiniteLoop(): never {
	while (true) {}
}

このinfiniteLoop関数は永遠にループし続けるため、戻り値の型はneverです。

型の絞り込み(型ガード)での使用

型の絞り込み(型ガード)を行う際に、never型が役立ちます。
特定の条件が満たされない場合にnever型を使用することで、到達不可能なコードを示すことができます。


function checkType(value: string | number): boolean {
	if (typeof value === 'string') {
		return true;
	} else if (typeof value === 'number') {
		return false;
	} else {
		// このコードに到達することはありません
		value; // (parameter) value: never
		return true;
	}
}

この例では、valuestringでもnumberでもない場合、到達不可能なコードとしてnever型が使用されています。

これらの場面では、never型がプログラムの予期しない部分を明示的に示し、コンパイラがコードの安全性をチェックするのに役立つでしょう。

switch × neverを使った網羅性チェック

ユニオン型を使ってswitch文で網羅性チェックを行う方法を見ていきましょう。
これにより、TypeScriptのコンパイラがすべてのケースを処理しているかどうかをチェックできるようにします。

例: ユニオン型の網羅性チェック

以下の例では、ユニオン型を使って異なるペットの種類を定義し、switch文でそれらの種類に基づいた処理を行います。
すべてのケースを網羅していることをコンパイラに保証するために、never型を活用しましょう。


type Pet = "Dog" | "Cat" | "Bird";

function getPetSound(pet: Pet): string {
	switch (pet) {
		case "Dog":
			return "Bow wow";
		case "Cat":
			return "Meow";
		case "Bird":
			return "Tweet tweet";
		default:
			return assertNever(pet);
	}
}

function assertNever(x: never): never {
	throw new Error("Unexpected value: " + x);
}

コードの解説

  1. ユニオン型の定義
    • type Pet = "Dog" | "Cat" | "Bird"では、"Dog""Cat""Bird"の3つのペットの種類を定義しています。
  2. switch文の使用
    • getPetSound関数は、switch文を使ってPetの値に応じてペットの鳴き声を返します。
  3. assertNever関数の呼び出し
    • switch文のdefaultケースでassertNever関数を呼び出します。
    • assertNever関数は、予期しない値が渡された場合に例外をスローし、戻り値の型としてneverを返します。

網羅性チェックの効果

この構造により、Petのすべてのケースがswitch文で処理されていることをコンパイラがチェックします。
もし、新しいペットの種類がPetに追加された場合、getPetSound関数にそのケースを追加しないと、コンパイル時にエラーが発生。
これにより、すべてのケースが確実に処理されるようにすることが可能です。


type Pet = "Dog" | "Cat" | "Bird" | "Mouse"; // 新しいペットの種類を追加

function getPetSound(pet: Pet): string {
	switch (pet) {
		case "Dog":
			return "Bow wow";
		case "Cat":
			return "Meow";
		case "Bird":
			return "Tweet tweet";
		default:
			// 型 'string' の引数を型 'never' のパラメーターに割り当てることはできません。ts(2345)
			return assertNever(pet);
	}
}

function assertNever(x: never): never {
	throw new Error("Unexpected value: " + x);
}

このようにして、never型を使った網羅性チェックを行うことで、コードの安全性とメンテナンス性を向上させることができます。

neverと似た特徴の型

TypeScriptには、never型と似た特徴を持つ他の型もいくつか存在します。
これらの型は、それぞれ異なる用途や意味を持っており、適切に使い分けることでコードの安全性と可読性を向上させることができます。
ここでは、never型と関連性のある型について見ていきましょう。

void型

void型は、関数が「値を返さない」ことを示します。
例えば、副作用を持つ関数やイベントハンドラなど、戻り値が必要ない場面で使われます。


function logMessage(message: string): void {
	console.log(message);
}

unknown型

unknown型は、「任意の型を受け取る」ことを示します。
any型と似ていますが、具体的な型に絞り込むまで操作が制限されるため、より安全です。


let value: unknown;
value = "Hello";
value = 42;

if (typeof value === "string") {
	console.log(value.toUpperCase());
}

any型

any型は、どんな型の値でも受け取ることができる非常に柔軟な型です。
ただし、型安全性が損なわれるため、なるべく使用を避けることが推奨されます。


let anything: any;
anything = "Hello";
anything = 42;
console.log(anything);

undefined型

undefined型は、「変数が値を持たない状態」を示します。
voidとは異なり、関数の戻り値としてundefinedを明示的に返すことも可能です。


function doNothing(): undefined {
	return undefined;
}

キャリア形成/給与還元
ひとつひとつ真摯に向き合う企業
ONE_WEDGE社員募集

株式会社 ONE WEDGEでは、新たな仲間を募集しています!

私たちと一緒に、革新的で充実したキャリアを築きませんか?
当社は、従業員が仕事と私生活のバランスを大切にできるよう、充実した福利厚生を整えています。

  • 完全週休2日制(土日休み)で、祝日や夏季休暇、年末年始休暇もしっかり保証!
  • 様々な休暇制度(有給、慶弔、産前・産後、育児、バースデー休暇)を完備!
  • 従業員の成長と健康を支援するための表彰制度、資格取得支援、健康促進手当など!
  • 生活を支えるテレワーク手当、記事寄稿手当、結婚祝金・出産祝金など、様々な手当を提供!
  • 自己啓発としての書籍購入制度や、メンバー間のコミュニケーションを深める交流費補助!
  • 成果に応じた決算賞与や、リファラル採用手当、AI手当など、頑張りをしっかり評価!
  • ワークライフバランスを重視し、副業もOK!

株式会社 ONE WEDGEでは、一人ひとりの従業員が自己実現できる環境を大切にしています。
共に成長し、刺激を与え合える仲間をお待ちしております。
あなたの能力と熱意を、ぜひ当社で発揮してください。
ご応募お待ちしております!

ホームページ、採用情報は下記ボタンからご確認ください!

応募、ご質問など、LINEでお気軽にご相談ください♪

まとめ

この記事では、TypeScriptのnever型について解説しました。
never型は「決して値を返さない」ことを示し、例外をスローする関数や無限ループに使われます。
また、型ガードによる到達不可能なコードを示す際にも使用され、コンパイラの安全性チェックを助けてくれるでしょう。

never型の理解を深めることで、TypeScriptのコードをより安全かつ読みやすくすることが可能です。
これを活用して、より堅牢なコードを書いていきましょう。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です