【実務・中級編】 ユーザー定義型ガード (isキーワード) – TypeScript実践ガイド

TypeScriptの「型ガード」で、泥臭いif文とさようならしよう

やあ。現場でコードを書いていて、「なぜか型が絞り込まれない」「`any`で逃げたくなる」そんな瞬間に遭遇したことはないかな?

TypeScriptを使いこなしているつもりでも、外部APIから返ってきたレスポンスや、複雑なUNION型の判定でハマることは誰にでもある。そんな時、`as`(型アサーション)で無理やり解決してしまうのは、いわば「後で爆発する時限爆弾」をコードに仕込んでいるようなものだ。

今回は、そんな惨状を防ぐための切り札、「ユーザー定義型ガード(Type Predicate)」について、現場の視点から深掘りしていく。

—

なぜ `is` キーワードが必要なのか?

TypeScriptの型システムは、コンパイル時にのみ存在する「幻」だ。ブラウザが実行するJavaScriptには、当然ながら`interface`も`type`も残っていない。

例えば、`if (typeof val === “string”)` と書けば、TypeScriptは「あ、これは文字列だな」と賢く理解してくれる(これを型絞り込み/Type Narrowingと呼ぶ)。しかし、自作の関数で複雑なオブジェクトを判定しようとした途端、TypeScriptは急に思考停止する。

// 悪い例:ただのbooleanを返すと、TypeScriptは中身を推論できない
function isUser(data: any): boolean {
return typeof data.name === ‘string’;
}

const data = { name: “Alice” };
if (isUser(data)) {
// ここで data.name にアクセスしようとすると、TypeScriptは「dataはanyだから知らん」と冷たくあしらう
console.log(data.name);
}

この「判断した事実」をコンパイラに伝えるためのパスポートが、`parameterName is Type` という構文だ。

—

実践:型ガードの書き方

まずは、現場でそのまま使えるクリーンな実装例を見てみよう。

type User = {
id: number;
name: string;
role: ‘admin’ | ‘user’;
};

/

  • ユーザー定義型ガード
  • dataがUser型であることを保証する

/
function isUser(data: unknown): data is User {
if (!data || typeof data !== ‘object’) return false;

// 必要なプロパティが揃っているか確認
const u = data as Record;
return (
typeof u.id === ‘number’ &&
typeof u.name === ‘string’ &&
(u.role === ‘admin’ || u.role === ‘user’)
);
}

// 現場での活用例
const response: unknown = await fetchUser(); // APIレスポンスは常に疑え

if (isUser(response)) {
// ここでは TypeScript は response が User 型だと「確信」している
console.log(`Welcome, ${response.name}. Role: ${response.role}`);
} else {
console.error(“無効なデータ形式です”);
}

なぜこれが「プロのコード」なのか

この書き方が現場で重宝される理由は3つある。

1. `unknown` 型の積極採用: 外部からのデータは `any` ではなく `unknown` で受けるのが現代の定石だ。`unknown` は「何者か分からない」という防衛線を張れる。型ガードを通すことで、安全に具象型へキャストできる。
2. 実行時の検証(Validation)と型定義の同期: TypeScriptは静的解析ツールだが、型ガードは「実行時のチェック」を強制する。これにより、APIの仕様変更があっても、このガード関数を修正するだけでシステム全体が型安全を維持できる。
3. 可読性の向上: 呼び出し元が `if (isUser(val))` と書くだけで済むため、ロジックが非常にスッキリする。

—

現場の先輩からのアドバイス:深追いは禁物

型ガードを多用するのは素晴らしいことだが、「なんでもかんでも型ガードを作ればいい」わけじゃないというのも覚えておいてほしい。

  • バリデーションライブラリの検討: `Zod` や `io-ts` のようなライブラリを使えば、型定義と実行時のバリデーションを同時に行える。手書きの型ガードはメンテナンスコストがかかるため、複雑なオブジェクト構造なら迷わずライブラリに頼れ。
  • 名前付けのルール: 型ガード関数は必ず `is…` で始めよう。これはTypeScript界隈の暗黙の了解であり、コードを読む他のメンバーが「あ、これは型ガード関数だな」と一瞬で理解するためのマナーだ。

—

まとめ

ユーザー定義型ガードは、TypeScriptという厳格な守護神と、JavaScriptという奔放な現実世界を繋ぐための「架け橋」だ。

`any`で思考停止するのをやめて、`is`キーワードでコンパイラに自信を持って指示を出そう。そうすれば、実行時エラーの数は劇的に減り、君の書くコードはより一層「堅牢で頼もしいもの」へと進化するはずだ。

さて、次は君のプロジェクトで散らばっている `as any` を、一つずつこの型ガードに置き換えていく作業から始めてみないか? それが、脱・中級者への最初の一歩だ。応援しているよ。

コメント

タイトルとURLをコピーしました