一般社団法人 全国個人事業主支援協会

COLUMN コラム

  • TypeScriptの型ガード完全ガイド:安全な型の絞り込み方

TypeScriptの型ガード完全ガイド:安全な型の絞り込み方

TypeScriptを書いていると、unknownunion型を扱う場面が必ず出てきます。そんなとき必要になるのが型ガードです。

この記事では、型ガードの4つの方法を実際のコードとともに解説します。

型ガードとは

型ガードとは、条件分岐によって変数の型を絞り込む仕組みです。TypeScriptコンパイラは、型ガードの結果を理解して、ブロック内での型を自動的に推論してくれます。

function example(value: string | number) {
  // ここでは value は string | number

  if (typeof value === "string") {
    // ここでは value は string に絞り込まれる
    console.log(value.toUpperCase());
  }
}

1. typeof による型ガード

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";
}

typeof で判定できる型

  • "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
  }
}

2. instanceof による型ガード

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();
  }
}

Errorの判定にも便利

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;
    }
  }
}

3. in 演算子による型ガード

in演算子は、オブジェクトが特定のプロパティを持っているかで判定します。

type Fish = {
  swim: () => void;
};

type Bird = {
  fly: () => void;
};

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    animal.swim();
  } else {
    animal.fly();
  }
}

APIレスポンスの判定に便利

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);
  }
}

4. ユーザー定義型ガード(is)

最も強力なのがユーザー定義型ガードです。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の型推論を最大限に活かせます。

  • プリミティブ型にはtypeof
  • クラスにはinstanceof
  • オブジェクトの構造で判定するならin
  • 複雑な判定にはisでカスタム型ガード

特に外部APIからのデータを扱う場合は、ユーザー定義型ガードで入り口をしっかり守ることで、アプリ内部の型安全性が保たれます。

この記事をシェアする

  • Twitterでシェア
  • Facebookでシェア
  • LINEでシェア