0Pricing
TypeScript Academy · レッスン

判別プロパティによる型の絞り込み

TypeScriptにswitch文内のバリエーションを絞り込ませます。

「判別プロパティによる型の絞り込み」はCoddyKit上の無料TypeScript Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはTypeScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 TypeScript Academyコースには全4レッスンが含まれています。

判別子による絞り込み

判別子をチェックすると、TypeScriptはユニオンを一致するメンバーに絞り込み、そのメンバー固有のフィールドを使えるようにします。これがこのパターンの利点です。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function area(s: Shape) {
  if (s.kind === "circle") return Math.PI * s.radius ** 2;
  return s.side ** 2;
}
console.log(area({ kind: "circle", radius: 2 }).toFixed(2));

判別子をswitchで処理する

判別子に対するswitchは、すべてのバリアントを処理する最も明確な方法です。各caseの中では、型が自動的に絞り込まれます。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function area(s: Shape): number {
  switch (s.kind) {
    case "circle": return Math.PI * s.radius ** 2;
    case "square": return s.side ** 2;
  }
}
console.log(area({ kind: "square", side: 5 }));

各caseで使えるメンバー固有のフィールド

"circle"のcaseではs.radiusを使えますが、s.sideは使えません。TypeScriptは現在どのメンバーを扱っているかを正確に把握しています。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function describe(s: Shape) {
  switch (s.kind) {
    case "circle": return "r=" + s.radius;
    case "square": return "side=" + s.side;
  }
}
console.log(describe({ kind: "circle", radius: 9 }));

ifによる絞り込み

switchを使う必要はありません。判別子を単純なifで比較しても、同じように効果的に絞り込めます。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function perimeter(s: Shape): number {
  if (s.kind === "circle") {
    return 2 * Math.PI * s.radius;
  }
  return 4 * s.side;
}
console.log(perimeter({ kind: "square", side: 3 }));

誤ったフィールドへのアクセスは失敗する

絞り込みを行う前は、メンバー固有のフィールドにアクセスできません。そのプロパティがすべてのメンバーに存在するわけではないため、TypeScriptがエラーを報告します。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function broken(s: Shape) {
  // Error: radius does not exist on Square
  // return s.radius;
  return s.kind;
}
console.log(broken({ kind: "square", side: 1 }));

boolean判別子による絞り込み

{ ok: true } | { ok: false }というユニオンでは、if (r.ok)をチェックすると成功メンバーに絞り込まれます。

type Result =
  | { ok: true; data: string }
  | { ok: false; error: string };

function handle(r: Result): string {
  if (r.ok) return "Data: " + r.data;
  return "Error: " + r.error;
}
console.log(handle({ ok: false, error: "boom" }));

早期returnによる絞り込み

一方のバリアントで早期returnすると、残りのコードでは他のバリアントに絞り込まれます。ケースを1つずつ処理していく、すっきりした方法です。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function label(s: Shape): string {
  if (s.kind === "circle") return "circle";
  // s is now narrowed to Square here
  return "square with side " + s.side;
}
console.log(label({ kind: "square", side: 8 }));

他の条件との組み合わせ

判別子のチェックを他のロジックと組み合わせることもできます。その分岐で判別子の条件が成立している限り、TypeScriptは絞り込みを維持します。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function bigCircle(s: Shape): boolean {
  return s.kind === "circle" && s.radius > 100;
}
console.log(bigCircle({ kind: "circle", radius: 150 }));

配列のfilterでの絞り込み

絞り込みはコールバックの中でも機能します。ここでは、反復処理を行いながら各図形を個別にチェックします。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

const shapes: Shape[] = [
  { kind: "circle", radius: 1 },
  { kind: "square", side: 2 }
];
shapes.forEach(s => {
  if (s.kind === "circle") console.log("c", s.radius);
  else console.log("s", s.side);
});

switchのreturnでも型安全性を維持できる

switchですべてのcaseを処理してreturnすると、TypeScriptは各caseの結果のユニオンから、正確な戻り値の型を推論します。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function tag(s: Shape) {
  switch (s.kind) {
    case "circle": return s.radius;
    case "square": return s.side;
  }
}
console.log(tag({ kind: "circle", radius: 4 }));

絞り込みのまとめ

switchとifのどちらを使う場合でも、判別子をチェックすることでメンバー固有のフィールドに安全にアクセスできます。次は、すべてのcaseが処理されることを保証します。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

function area(s: Shape): number {
  return s.kind === "circle" ? Math.PI * s.radius ** 2 : s.side ** 2;
}
console.log(Math.round(area({ kind: "circle", radius: 10 })));

クイックチェック:絞り込み

判別子による絞り込みについての理解度を確認しましょう。

まとめ:判別子による絞り込み

switchやifで判別子をチェックすると、ユニオンが1つのメンバーに絞り込まれ、そのメンバーに固有のフィールドだけが公開されることを学びました。早期returnや条件の組み合わせでも、絞り込みは維持されます。

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number };

const s: Shape = { kind: "square", side: 7 };
console.log(s.kind === "square" ? s.side : 0);

よくある質問

「判別プロパティによる型の絞り込み」レッスンは無料ですか?

はい。「判別プロパティによる型の絞り込み」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、TypeScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 TypeScript Academyコースには全4レッスンが含まれています。

「判別プロパティによる型の絞り込み」で何を学びますか?

TypeScriptにswitch文内のバリエーションを絞り込ませます。 ブラウザで直接実行するハンズオンコードでTypeScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

TypeScript Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのTypeScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「判別プロパティによる型の絞り込み」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このTypeScript Academyレッスンでコードを書いて実行できますか?

はい。すべてのTypeScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 判別可能なユニオンの構築
  2. 判別プロパティによる型の絞り込み
  3. neverによる網羅性チェック
  4. ステートマシンのモデル化
← TypeScript Academyに戻る