TypeScriptの型狭め(Narrowing)と型ガードを完全解説!初心者でも理解できる安全なプログラミング
生徒
「TypeScriptで値が複数の型になれるとき、どうやって安全に処理したらよいですか?」
先生
「そのとき役立つ考え方が、型狭め(Narrowing)と型ガードです。TypeScriptが型を判断できるように導いてあげる仕組みですね。」
生徒
「型を判断できなかったら何か問題が起こるんですか?」
先生
「たとえば数値だと思って計算しようとしたら実は文字列だった、というときにエラーが発生します。だから安全に扱うためにも、型狭めと型ガードを理解しておくことが大切です。」
1. 型狭め(Narrowing)とは?
TypeScriptでは変数が複数の型を持つことがあります。これはユニオン型と呼ばれます。例えばstring | numberという型は、文字列・数値どちらでも入る状態です。このままでは、TypeScriptは「どちらの型か分からない」ため、数値向け、文字列向けの操作ができなくなります。
そこで、条件分岐などを使って「この時点では数値だよ」とTypeScriptに教えることで、型を絞り込むことができます。これを型狭め(Narrowing)と言います。プログラムがより安全になり、間違いを防げます。
function printLength(value: string | number) {
if (typeof value === "string") {
console.log(value.length);
}
}
上の例ではtypeofを使ってvalueが文字列であることを確認しているため、.lengthを安全に使えるようになります。
2. 型ガード(Type Guard)とは?
型ガードは、ある変数が特定の型であることを判定する仕組みのことです。型ガードを使うことでTypeScriptが「この条件の中ではこの型なんだ!」と理解し、型狭めを自動で行ってくれます。
型ガードは、型を守るための番犬のような存在です。「安全な型だけを中に通す!」というイメージを持つと分かりやすいです。
型ガードにはいくつか種類があり、ここでは代表的なものを紹介します。
3. 代表的な型ガードの方法
3-1. typeof を使った型ガード
数値・文字列などの基本的な型を判定します。
function showValue(x: string | number) {
if (typeof x === "number") {
console.log(x.toFixed(2));
} else {
console.log(x.toUpperCase());
}
}
typeofを使うことで、それぞれに対応したメソッドが安全に使えます。
3-2. in 演算子による型ガード
オブジェクトに特定のプロパティがあるかチェックして型を絞ります。
type Dog = { bark: () => void };
type Cat = { meow: () => void };
function speak(animal: Dog | Cat) {
if ("bark" in animal) {
animal.bark();
} else {
animal.meow();
}
}
inを使うと、どちらの動物か確実に判断できます。
3-3. 比較演算子を使った型狭め
nullやundefinedをチェックするケースでも使います。
function hello(name?: string) {
if (name !== undefined) {
console.log("Hello " + name);
}
}
これによってnameが文字列として安全に扱えます。
4. カスタム型ガード(ユーザーが作る型ガード)
自分で型判定をする関数を作ることもできます。関数が特別な形でbooleanを返すと、TypeScriptが型狭めをしてくれます。
type User = { name: string };
type Guest = { guest: true };
function isUser(obj: User | Guest): obj is User {
return "name" in obj;
}
function greet(person: User | Guest) {
if (isUser(person)) {
console.log("ようこそ!" + person.name + "さん");
} else {
console.log("ゲストの方ですね!");
}
}
obj is Userと書くことで、「この関数がtrueを返したらUser型」と理解させています。非常に便利な型ガードです。
5. なぜ型狭めと型ガードが必要なの?
型狭めと型ガードを学ぶことで、以下のメリットがあります。
- 実行時エラーを未然に防げる
- プログラムが安全に動作する
- コード補完が正確になって開発効率アップ
- 大規模なプロジェクトでも安心して型を管理できる
特に、ユニオン型を多く使うTypeScriptでは必須の考え方です。最初は難しそうに感じますが、慣れるととても強力な武器になります!
まとめ
型狭め(Narrowing)と型ガードの全体像を振り返る
この記事では、TypeScriptにおける型狭め(Narrowing)と型ガード(Type Guard)について、初心者でも理解できるように順を追って解説してきました。TypeScriptは「複数の型を許容できる」柔軟な言語ですが、その柔軟さは同時に「安全に扱わなければエラーにつながる」という側面も持っています。そこで重要になるのが、今この変数が「どの型なのか」を明確にする考え方です。
型狭めとは、条件分岐などを使ってTypeScriptに型情報を伝え、扱える型の範囲を絞り込む仕組みです。そして型ガードは、その型狭めを成立させるための具体的な判定方法です。両者は別々の概念ではなく、常にセットで使われる重要な考え方だと言えます。
ユニオン型と型狭めの関係性
TypeScriptでは、string | numberのようなユニオン型を使うことで、ひとつの変数に複数の型を持たせることができます。しかし、そのままではTypeScriptは安全な操作を許可してくれません。なぜなら、文字列向けの処理なのか、数値向けの処理なのかを判断できないからです。
そこで登場するのが型狭めです。typeofや比較演算子を使って条件を分岐することで、「このブロックの中では文字列」「この処理では数値」とTypeScriptに伝えられます。これにより、コンパイル時に型が確定し、安全なメソッド呼び出しが可能になります。ユニオン型を使うなら、型狭めは必須の知識です。
代表的な型ガードを正しく使い分ける
型ガードにはいくつかの代表的な方法があります。typeofは基本型の判定に向いており、数値や文字列、真偽値などを扱う場面でよく使われます。一方、オブジェクトを扱う場合にはin演算子が有効です。特定のプロパティが存在するかどうかを調べることで、どの型かを判断できます。
また、nullやundefinedのチェックも重要な型狭めの一種です。値が存在するかどうかを明示的に確認することで、その後の処理を安全に進められます。これらの基本的な型ガードを正しく使えるようになると、TypeScriptのエラーは一気に減っていきます。
カスタム型ガードがもたらす設計の自由度
記事の中で紹介したカスタム型ガードは、より高度で実践的なテクニックです。obj is Userのような戻り値の型を指定することで、「この関数がtrueを返した場合は、この型である」とTypeScriptに伝えられます。これにより、複雑な条件判定でも型狭めを自動的に行えるようになります。
カスタム型ガードは、ユニオン型が増えがちな実務のコードで特に効果を発揮します。認証済みユーザーと未認証ユーザー、管理者と一般ユーザーなど、役割によって構造が異なるデータを安全に扱えるようになります。コードの可読性も向上し、意図が伝わりやすい設計になります。
総合サンプル:型狭めと型ガードを組み合わせた実践例
type SuccessResponse = { status: "success"; data: string };
type ErrorResponse = { status: "error"; message: string };
type ApiResponse = SuccessResponse | ErrorResponse;
function handleResponse(res: ApiResponse) {
switch (res.status) {
case "success":
console.log("成功:" + res.data);
break;
case "error":
console.log("エラー:" + res.message);
break;
}
}
この例では、リテラル型とユニオン型を組み合わせ、switch文による型狭めを行っています。statusの値によって型が自動的に判定されるため、それぞれのプロパティを安全に扱えます。このような書き方は、APIレスポンス処理や状態管理で頻繁に使われる実践的なパターンです。
生徒
「型狭めって、ただの条件分岐だと思っていましたが、TypeScriptに型を教える大事な役割があるんですね。」
先生
「その通りです。人間だけでなく、TypeScriptにも状況を説明してあげるイメージですね。」
生徒
「型ガードを使うと、エラーを先に防げるのがすごく安心だと感じました。」
先生
「それがTypeScriptの強みです。安全なプログラミングを支える基礎になります。」
生徒
「これからユニオン型を使うときは、必ず型狭めを意識して書いてみます。」
先生
「ぜひ実践してください。コードの質が確実に変わりますよ。」