TypeScriptで型ガードのテストを書くときの注意点を徹底解説!初心者でも理解できる安全な型判定
生徒
「TypeScriptの型ガードをテストするとき、どう書けば良いかわからなくて困っています。」
先生
「型ガード(type guard)は、ユニオン型や複雑な型を安全に判定するためにとても便利だよ。でもテストを書くときには、少しポイントが必要なんだ。」
生徒
「間違えたテストを書いても気づけないことがあるんですか?」
先生
「うん。型ガードはTypeScript独自の仕組みだから、テストの方法を理解していないと正しく動いているように“見えてしまう”ことがあるんだ。今日はそこを丁寧に学んでいこう!」
1. 型ガードとは?初心者でもわかる基本の説明
型ガードとは、値が特定の型であるかどうかを判定する仕組みです。TypeScriptでは、is演算子を使うことで型を絞り込み(型狭め)ができ、間違った型によるエラーを防げます。
たとえば数値と文字列のどちらも受け取れる変数に対して、それが数値かどうか判定して安全に処理を進めるときに役立ちます。
function isNumber(value: unknown): value is number {
return typeof value === "number";
}
function printValue(value: number | string) {
if (isNumber(value)) {
console.log(value.toFixed(2));
} else {
console.log(value.toUpperCase());
}
}
2. 型ガードのテストが難しい理由
型ガードはTypeScriptのコンパイル時に型推論へ影響しますが、JavaScript実行時にはただの関数に見えます。そのため、以下のような勘違いが起きやすいのです。
- コンパイルエラーが起きないから正しいと思ってしまう
- テストが成功しても型の判定が間違っている可能性がある
テストでは「本当に意図した型判定が行われているか」を意識する必要があります。
3. Jestを使った型ガードのテスト例
もっとも大事なポイントは、正しく型を判定しているときと間違っているときの両方をテストすることです。
// 型ガードの関数
function isString(value: unknown): value is string {
return typeof value === "string";
}
// テストコード例
test("isStringは文字列を判定できる", () => {
expect(isString("Hello")).toBe(true);
});
test("isStringは文字列以外ではfalseになる", () => {
expect(isString(123)).toBe(false);
expect(isString(null)).toBe(false);
expect(isString(undefined)).toBe(false);
});
4. 型推論が正しく行われているか確認する方法
型ガードの本当の役割は、安全な型の絞り込みです。テストの中でも型の扱いが変わっていることを確かめましょう。
test("isStringで型が絞り込まれることを確認", () => {
const value: unknown = "ChatGPT";
if (isString(value)) {
// 型はstringになっている!
console.log(value.toUpperCase());
}
});
CHATGPT
もし型推論が効いていなければ、value.toUpperCase()でエラーが出ます。これが型ガードが正しく機能している証拠になります。
5. 実際の開発で気をつけるポイント
実務では型ガードを外部APIのデータチェックなどに使います。その際に注意すべきことをまとめます。
- 返り値は必ず
value is 型を使う(布形式にしない) - 異常系(判定失敗)のテストを忘れない
- オブジェクトの型ガードはプロパティ存在チェックを丁寧に
- 型ガードが複雑化したら処理を分割する
type User = { name: string; age: number };
function isUser(obj: any): obj is User {
return obj && typeof obj.name === "string" && typeof obj.age === "number";
}
このようにプロパティを一つずつチェックすると間違いが減ります。
6. nullとundefinedに特に注意しよう
型ガードをテストするとき、多くの人が見落とすのが null と undefined です。JavaScriptではnullもobject扱いになるため、判定に失敗しやすくなります。
test("nullやundefinedは正しく弾くべき", () => {
expect(isUser(null)).toBe(false);
expect(isUser(undefined)).toBe(false);
});
このケースをテストしないと、動作がおかしくても気づきません。
7. 手動テストだけでなく自動テストを活用する
型ガードはアプリケーションの安全性に直接関わる機能です。ユニオン型やリテラル型を扱う場面では必ずテストを自動化しましょう。
プログラムの変更があっても、型の安全性を壊していないか確認できます。
まとめ
型ガードのテストは「型安全」を守るための最後の砦
この記事では、TypeScriptにおける型ガードのテスト方法について、初心者にも理解しやすい形で詳しく解説してきました。 型ガードは、ユニオン型や複雑なデータ構造を安全に扱うための重要な仕組みですが、 その正しさはテストを書かなければ保証できないという点が大きな特徴です。 なぜなら、型ガードはTypeScriptのコンパイル時に型推論へ影響を与える一方で、 実行時には単なる関数として振る舞うため、間違った実装でも一見正しく動いているように見えてしまうからです。
特に実務では、外部APIやユーザー入力など「信頼できないデータ」を扱う場面が多く、 型ガードの誤りはアプリケーション全体の安全性を損なう原因になります。 だからこそ、型ガード専用のテストを書き、 「正しい入力ではtrueになるか」「間違った入力ではfalseになるか」を丁寧に確認することが欠かせません。
型ガードのテストで意識すべき基本ポイント
型ガードのテストを書く際に最も重要なのは、 正常系と異常系の両方を必ず確認することです。 文字列を判定する型ガードであれば、文字列だけでなく、 数値、null、undefined、オブジェクトなども入力として与え、 正しくfalseが返るかを検証する必要があります。 この確認を怠ると、想定外の値を通してしまう危険な型ガードが完成してしまいます。
また、テストでは単にtrueやfalseを確認するだけでなく、 型推論が正しく働いているかにも注目しましょう。 型ガードが正しく実装されていれば、 if文の中でTypeScriptが型を絞り込み、 その型専用のメソッドが安全に呼び出せるようになります。 これこそが、型ガードを使う本来の目的です。
サンプルで振り返る型ガードテストの考え方
type Product = {
name: string;
price: number;
};
function isProduct(value: unknown): value is Product {
return (
typeof value === "object" &&
value !== null &&
typeof (value as any).name === "string" &&
typeof (value as any).price === "number"
);
}
// テスト例
test("isProductは正しいオブジェクトを判定できる", () => {
const data = { name: "Book", price: 1500 };
expect(isProduct(data)).toBe(true);
});
test("isProductは不正なデータを弾く", () => {
expect(isProduct({ name: "Book" })).toBe(false);
expect(isProduct(null)).toBe(false);
expect(isProduct(123)).toBe(false);
});
このように、型ガードのテストでは「通してよいデータ」と「通してはいけないデータ」を明確に分けて確認します。 特にnullやundefinedは見落とされやすいため、必ずテストケースに含めることが重要です。 こうしたテストを用意しておくことで、 後からコードを修正した際にも型安全性が壊れていないかを自動で確認できます。
自動テストが型ガードの信頼性を高める
型ガードは、アプリケーション全体の安全性を支える重要な部品です。 手動テストだけに頼ると、修正や機能追加のたびに確認漏れが発生しやすくなります。 Jestなどのテストフレームワークを使って自動テストを書いておけば、 型ガードの振る舞いが常に一定であることを保証できます。
TypeScriptの強みは「型による安心感」ですが、 その安心感を本当の意味で支えているのが、こうしたテストの積み重ねです。 型ガードとテストをセットで考える習慣を身につけることで、 初心者から一歩進んだ、信頼性の高いコードを書けるようになります。
生徒
「型ガードって書くだけで安心だと思っていましたが、 テストを書かないと危ない場合もあるんですね。」
先生
「そうなんです。型ガードは便利ですが、実装ミスに気づきにくいのでテストが重要なんですよ。」
生徒
「trueになるケースとfalseになるケースを両方テストするのが大事だと分かりました。」
先生
「その意識があれば、型安全なプログラムを書けていますね。」
生徒
「これからは型ガードを書くとき、必ずテストも一緒に書きます!」
先生
「それができれば、TypeScriptを正しく使いこなせていますよ。」