TypeScriptを書いていると、unknownやunion型を扱う場面が必ず出てきます。そんなとき必要になるのが型ガードです。
この記事では、型ガードの4つの方法を実際のコードとともに解説します。
型ガードとは、条件分岐によって変数の型を絞り込む仕組みです。TypeScriptコンパイラは、型ガードの結果を理解して、ブロック内での型を自動的に推論してくれます。
function example(value: string | number) {
// ここでは value は string | number
if (typeof value === "string") {
// ここでは value は string に絞り込まれる
console.log(value.toUpperCase());
}
}
typeofはプリミティブ型の判定に使います。
function formatValue(value: string | number | boolean): string {
if (typeof value === "string") {
return value.trim();
}
if (typeof value === "number") {
return value.toFixed(2);
}
// ここでは value は boolean
return value ? "Yes" : "No";
}
"string""number""boolean""undefined""object" (nullも含まれるので注意)"function""symbol""bigint"typeof nullは"object"を返します。nullチェックは別途行いましょう。
function process(value: object | null) {
// ダメな例
if (typeof value === "object") {
// value はまだ object | null
}
// 良い例
if (value !== null && typeof value === "object") {
// value は object
}
}
instanceofはクラスのインスタンス判定に使います。
class Dog {
bark() {
console.log("ワン!");
}
}
class Cat {
meow() {
console.log("ニャー");
}
}
function speak(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
async function fetchData(url: string) {
try {
const response = await fetch(url);
return await response.json();
} catch (error) {
if (error instanceof TypeError) {
console.error("ネットワークエラー:", error.message);
} else if (error instanceof SyntaxError) {
console.error("JSONパースエラー:", error.message);
} else {
throw error;
}
}
}
in演算子は、オブジェクトが特定のプロパティを持っているかで判定します。
type Fish = {
swim: () => void;
};
type Bird = {
fly: () => void;
};
function move(animal: Fish | Bird) {
if ("swim" in animal) {
animal.swim();
} else {
animal.fly();
}
}
type SuccessResponse = {
status: "success";
data: unknown;
};
type ErrorResponse = {
status: "error";
message: string;
};
type ApiResponse = SuccessResponse | ErrorResponse;
function handleResponse(response: ApiResponse) {
if ("data" in response) {
console.log("成功:", response.data);
} else {
console.error("エラー:", response.message);
}
}
最も強力なのがユーザー定義型ガードです。isキーワードを使って、任意の判定ロジックで型を絞り込めます。
type User = {
id: number;
name: string;
email: string;
};
function isUser(value: unknown): value is User {
return (
typeof value === "object" &&
value !== null &&
"id" in value &&
"name" in value &&
"email" in value &&
typeof (value as User).id === "number" &&
typeof (value as User).name === "string" &&
typeof (value as User).email === "string"
);
}
// 使用例
function processUser(data: unknown) {
if (isUser(data)) {
// data は User型として扱える
console.log(`ユーザー: ${data.name} (${data.email})`);
} else {
console.error("不正なデータ形式");
}
}
const items: (string | null | undefined)[] = [
"apple",
null,
"banana",
undefined,
"cherry",
];
// 型ガード関数
function isNotNullish<T>(value: T | null | undefined): value is T {
return value != null;
}
// filter後の型が string[] になる
const fruits = items.filter(isNotNullish);
console.log(fruits); // ["apple", "banana", "cherry"]
| 方法 | 使う場面 |
|---|---|
typeof |
プリミティブ型(string, number, boolean等)の判定 |
instanceof |
クラスのインスタンス判定 |
in |
オブジェクトのプロパティ有無で判定 |
is(ユーザー定義) |
複雑な判定ロジックが必要なとき |
型ガードを適切に使うことで、TypeScriptの型推論を最大限に活かせます。
typeofinstanceofinisでカスタム型ガード特に外部APIからのデータを扱う場合は、ユーザー定義型ガードで入り口をしっかり守ることで、アプリ内部の型安全性が保たれます。