TypeScriptの型ガードの使い方をやさしく解説!typeof・in・instanceofで安全に型チェック
生徒
「TypeScriptで、変数の中身がどんな種類なのかを確認する方法ってありますか?」
先生
「はい、TypeScriptでは型ガード(Type Guard)という仕組みを使って、変数の中身の種類を判別できます。」
生徒
「どうやって判別するんですか?難しそう…」
先生
「安心してください。typeof、in、instanceofという3つの方法を使えば、初心者でも簡単に型チェックできますよ!これから一つずつわかりやすく見ていきましょう。」
1. 型ガードとは?
型ガード(Type Guard)とは、「この値はいまどんな種類なのか?」を判断して、プログラムが安全に動くように手助けしてくれる仕組みです。TypeScriptでは変数が複数の型を取りうることがありますが、型ガードを使うことで、状況に応じて正しい処理を選べるようになります。
たとえば「文字を受け取ったらメッセージを表示し、数値を受け取ったら計算する」というように、型ごとに動作を変えたいときにとても役立ちます。型をしっかり見分けることで、エラーの発生を防ぎ、コードの読みやすさもぐっと高まります。
次の例のように、型ガードを使わずに処理を書こうとすると、どちらの型にも対応するために複雑になりがちです。
function show(value: string | number) {
// このままだと、valueが文字列か数値か分からない
console.log("受け取った値:", value);
}
show("こんにちは");
show(10);
しかし、型ガードを使えば型を見極められるため、次のように「文字列ならこうする」「数値ならこうする」と明確に書き分けられます。
function show(value: string | number) {
if (typeof value === "string") {
console.log("文字列として扱います:", value);
} else {
console.log("数値として扱います:", value * 2);
}
}
このように、型ガードはTypeScriptの特徴である「型の安全性」を最大限に引き出し、初心者でも安心してコードを書けるようにしてくれる大切な機能です。
2. typeof を使った型ガード
typeofは、変数がどんな種類の値なのかを確認するためのもっとも基本的な型ガードです。特に「文字列なのか数値なのか」といったプリミティブ型の判定に強く、TypeScriptでも非常によく使われます。
型ガードを使わないと、1つの変数に複数の型が入りうる場合、どの処理が正しいのか判断しにくくなります。しかしtypeofを使えば、実行中の値を調べて安全に処理を分岐できます。
function printValue(value: string | number) {
if (typeof value === "string") {
console.log("文字列として処理します:" + value);
} else if (typeof value === "number") {
console.log("数値として計算します:" + (value * 2));
}
}
printValue("こんにちは");
printValue(123);
文字列として処理します:こんにちは
数値として計算します:246
このように、typeofを使うと、文字列なら文字列用の処理、数値なら数値用の処理と明確に分けることができます。特に「画面にメッセージを表示する」「数値を計算する」といった異なるジャンルの処理をまとめたい場合に大活躍します。
ただし、typeofが使えるのは基本的な値(string、number、boolean、undefined、symbol、bigint、function、object)の判定だけで、オブジェクトの細かい形までは判別できません。「オブジェクトの違いを見分けたい場合」は別の型ガードが必要になります。
3. in を使った型ガード
in演算子は、オブジェクトの中に特定のプロパティ(名前)があるかどうかを調べるための型ガードです。「このオブジェクトは犬なのか?猫なのか?」といったように、持っている機能の違いで判断したいときにとても便利です。
イメージとしては、「この箱にはリモコンが入っているか?それとも本が入っているか?」を、中身の種類ではなく入っている物の名前で見分けるような感覚です。TypeScript のオブジェクトも、「このプロパティがあるならこの型だな」と判断できます。
type Dog = { bark: () => void };
type Cat = { meow: () => void };
function speak(animal: Dog | Cat) {
if ("bark" in animal) {
// animal の中に bark プロパティがあれば Dog とみなせる
animal.bark();
} else {
// bark がないので、ここでは Cat として扱える
animal.meow();
}
}
speak({ bark: () => console.log("ワン!") });
speak({ meow: () => console.log("ニャー!") });
ワン!
ニャー!
この例では、Dog | Catという「犬か猫か分からない」状態の引数 animal を受け取っています。そのままでは bark も meow も安全には呼べませんが、"bark" in animal というチェックを入れることで、「このオブジェクトは吠える機能(bark)を持っているから Dog だ」と判断できるようになります。
反対に、bark がなければ Cat だと分かるので、安心して meow() を呼び出せます。このように、in を使うと「どんなプロパティを持っているか」でオブジェクトの型を絞り込めるため、複数の型をまとめて扱うときに大きな力を発揮します。
もう少し身近な例として、「年齢を持っているユーザーだけ特別なメッセージを出したい」といった場合も、in を使うとすっきり書けます。
type BasicUser = { name: string };
type DetailUser = { name: string; age: number };
function showUser(user: BasicUser | DetailUser) {
if ("age" in user) {
console.log(`${user.name} さんは ${user.age} 歳です。`);
} else {
console.log(`${user.name} さんは年齢未入力です。`);
}
}
このように、in 演算子を使った型ガードは、TypeScript のオブジェクト型を安全に扱うための基本テクニックです。「このプロパティがあるならこの型」と自然に読めるコードになるので、初心者でも直感的に理解しやすくなります。
4. instanceof を使った型ガード
instanceofは、「この変数が、あるクラスから作られたインスタンス(実体)かどうか」を判定できます。
クラス(class)とは、モノの設計図のようなものです。たとえば「犬」というクラスから、「ポチ」という犬のデータを作ったとき、その「ポチ」は「犬クラスのインスタンス」と呼ばれます。
class Car {
drive() {
console.log("車を運転します");
}
}
class Bike {
ride() {
console.log("自転車に乗ります");
}
}
function move(vehicle: Car | Bike) {
if (vehicle instanceof Car) {
vehicle.drive();
} else {
vehicle.ride();
}
}
move(new Car());
move(new Bike());
車を運転します
自転車に乗ります
instanceofは、クラスを使っているときに使える便利な型ガードです。
5. どの型ガードを使うべき?
typeofは、文字列や数値などの基本的な値のチェックに使います。inは、オブジェクトのプロパティの存在を調べたいときに使います。instanceofは、クラスを使って作られたデータかどうかを確認したいときに使います。
この3つを使いこなせると、TypeScriptで安全で読みやすいコードが書けるようになります。
まとめ
TypeScriptでコードを書くとき、型を安全に判別して処理を分けることはとても大切です。特に現代のフロントエンド開発やAPIのデータ処理では、1つの関数に複数の型が渡る場面がよくあります。そのまま処理するとエラーやバグの原因になるため、今回学んだ型ガードを使うことで、型に応じて正しく振る舞わせることができるようになります。
型ガードの基本は3つの方法です。
まずtypeofを使えば、数値や文字列などの基本型を簡単に判別できます。次にinは、オブジェクトに特定のプロパティがあるかどうかを確認するのに便利で、構造的な判定に向いています。そしてinstanceofは、クラスのインスタンスかどうかを調べたいときに活躍します。
以下に、3つの型ガードを組み合わせたサンプルコードを紹介します。
サンプル:すべての型ガードを使って安全に処理を分岐
class Dog {
bark() {
console.log("ワンワン!");
}
}
class Cat {
meow() {
console.log("ニャーニャー!");
}
}
function handle(value: string | number | Dog | Cat) {
if (typeof value === "string") {
console.log("文字列です:" + value.toUpperCase());
} else if (typeof value === "number") {
console.log("数値です:" + (value * 2));
} else if (value instanceof Dog) {
value.bark();
} else if ("meow" in value) {
value.meow();
}
}
handle("こんにちは");
handle(10);
handle(new Dog());
handle(new Cat());
文字列です:コンニチハ
数値です:20
ワンワン!
ニャーニャー!
このように、typeof・in・instanceofをうまく組み合わせることで、どんな型が来ても安全に処理できるようになります。
実務でも、APIから返ってくるデータや、ユーザーの操作で動的に変わる値を扱うときに、型ガードを使って型をしっかり見極めることがバグの防止に直結します。
特にin演算子は、型のユニオン(複数型のどれか)を扱うときに大きな効果を発揮します。プロパティの存在チェックを活用すれば、明示的に型を分けて安全に処理を進めることができ、コードの可読性もぐんと上がります。
また、クラスベースで設計されたアプリケーションでは、instanceofでインスタンスの判定を行うことで、責任を持った処理の流れが書けるようになります。
型ガードは、TypeScriptの型システムを活かしきるための大切な技術です。これからも実際のコードにどんどん取り入れて、型安全な開発を目指していきましょう。
生徒
「先生、型ガードって最初は難しそうって思ったけど、やってみたら意外とわかりやすかったです!」
先生
「それはよかったですね。特にtypeofはJavaScriptでもおなじみの構文なので、入りやすかったのではないでしょうか。」
生徒
「はい!あと、オブジェクトにinを使ったチェックとか、クラスのinstanceofも実務でよく使えそうです!」
先生
「その通りです。型ガードはコードの安全性を高めるだけでなく、読みやすくてバグの少ないプログラムを書く助けにもなりますよ。」
生徒
「APIからいろんな型のデータが返ってくるときなんかも、型ガードでしっかり処理を分けられそうですね!」
先生
「ええ、その意識が大切です。これからTypeScriptのコードを書くときは、ぜひ型ガードを自然に取り入れていってくださいね。」