TS初めてのTypeScript

Day 3ユニオン・絞り込み・ジェネリクス(読める範囲で)

型の絞り込み(narrowing)

ユニオン型を安全に扱うため、条件分岐で型を1つに絞り込む方法を学ぶ。

ユニオン型はそのままだと使いにくい

string | number という値があるとき、いきなり文字列専用のメソッドを呼ぶことはできません。文字列かもしれないし数値かもしれないからです。そこで if などで条件を確認し、その分岐の中では「今は文字列だ」と型を1つに狭めます。これを型の絞り込み(narrowing)と呼びます。

TYPESCRIPT
function format(value: string | number): string {
  if (typeof value === "string") {
    // このブロックの中では value は string 扱い
    return value.toUpperCase();
  }
  // ここまで来たら value は number 扱い
  return value.toFixed(2);
}
typeof で分岐すると、各ブロック内で型が絞り込まれる

なぜ絞り込みが必要か

TypeScriptは「まだ文字列か数値か分からない値」に対して、文字列専用の操作を許しません。もし許すと、数値のときに toUpperCase() を呼んで実行時エラーになるからです。絞り込みは「今この分岐では安全に使える」ことを型で証明する仕組みです。

絞り込みの手段はいくつかあります。値の種類を調べる typeof、リテラル型を直接比較する ===、値が存在するかを確認する if などです。特にリテラルのユニオンでは === が主役になります。

TYPESCRIPT
type Status = "idle" | "loading" | "done";

function label(status: Status): string {
  if (status === "loading") {
    return "読み込み中...";
  }
  if (status === "done") {
    return "完了しました";
  }
  return "待機中"; // ここでは status は "idle" に絞られている
}
リテラルのユニオンは === で1つずつ絞り込む

絞り込まずに使う

文字列か数値か分からないまま操作しようとする

TYPESCRIPT
function f(v: string | number) {
  return v.toUpperCase(); // エラー: number には無い
}

絞り込んでから使う

typeof で確認した分岐の中でだけ操作する

TYPESCRIPT
function f(v: string | number) {
  if (typeof v === "string") return v.toUpperCase();
  return String(v);
}

「値があるか」の確認も絞り込み

string | undefined のような型では、いきなり使うとエラーになります。if (value) { ... } のように存在を確認すると、その中では undefined が除かれた型に絞り込まれます。AIが生成したコードで赤線が出たら、多くはこの確認が抜けているのが原因です。

AIにはこう聞く

「この関数の引数は string | number。分岐で型を絞り込んで、それぞれ適切に処理して」と頼むと、typeof を使った安全な分岐を書いてくれます。赤線が残ったら「絞り込みが足りない箇所を教えて」と続けて聞きましょう。

読んでも腑に落ちない所は、AIに噛み砕いてもらいましょう。

理解度チェック

答えられれば、面接で説明できる状態に一歩近づきます。

Q1

value: string | number に対して value.toFixed(2) を安全に呼ぶには、どの絞り込みが必要?

Q2

型の絞り込み(narrowing)を最もよく表しているのはどれ?

Q3

string | undefined 型の値をそのまま使うと赤線が出ます。なぜ出るのか、どう対処するのかを説明してください。

記述式です。まず自分の言葉で答えを考えてから、模範解答を開いて自己採点してください。