📚

判別可能なUnion型

2020/09/30に公開1

はじめに

今回の判別可能なUnion型とは、いうなればin演算子に取って代わる型ガードのための手法だと筆者は考えます。
つまりin演算子の問題点を補ってくれるのが判別可能なUnion型ということです。
型ガードについては以前記事にしましたので参考にして下さい!


in演算子

前回の型ガードの復習も兼ねて、以下コード上で見ていきましょう。

interface Person {
  name: string;
  age: number;
}
interface Book {
  name: string;
  price: number;
}

function doStuff(arg: Person | Book) {
  console.log(arg.name);
  console.log(arg.age);// エラー(プロパティ 'age' は型 'Book' に存在しません。)

}

interfaceでオブジェクトの型を定義し、doStuffという関数の引数にユニオン型でインターフェース名を渡しています。返り値は型推論からもvoid型でログを2つ表示させようとしています。

当然、arg.ageについてはエラーが発生します。エラー内容から分かるようにargがPersonかBookどちらは型を絞り込めていないためエラーが生じています。

そのため、in演算子による型ガードを使えばこのエラーは解消されます。

interface Person {
  name: string;
  age: number;
}
interface Book {
  name: string;
  price: number;
}

function doStuff(arg: Person | Book) {
  if ("age" in arg) {
    console.log(arg.age);
  } else {
    console.log(arg.price);
  }
  console.log(arg.name);
}}

in演算子の何が問題やねん

筆者が思うin演算子の最大のデメリットは、if文の中でプロパティ名を過って記述した場合Typescriptはエラーを出してくれない,またvscodeによる自動補完によるサポートがないことだと思います。
どういうことかコードで確認しましょう。

interface Person {
  name: string;
  age: number;
}
interface Book {
  name: string;
  price: number;
}

function doStuff(arg: Person | Book) {
  if ("aggge" in arg) {//'age'の間違え(エラーなし)
    console.log(arg.age); //agggeとプロパティは存在しないためここではエラーを出してくれる。
  } else {
    console.log(arg.price);
  }
  console.log(arg.name);
}

ageの部分をagggeとタイポしています。agggeというプロパティがあるかもしれないと判断してなのか、このagggeとタイポした時点ではエラーを出してくれません。

このような簡単なコードならすぐに間違いに気づくかもしれませんが、より複雑なコードを書く中でこのようなタイポによる間違いは是非ともvscodeさんエラーを出してほしいです。笑


ユーザー定義型ガード

前置きが長くなりましたが、in演算子に代わる手法がユーザー定義型ガードです。

interface Person {
  type: "person";
  name: string;
  age: number;
}
interface Book {
  type: "book";
  name: string;
  price: number;
}

function doStuff(arg: Person | Book) {
  if (arg.type === "person") {
    console.log(arg.age);
  } else {
    console.log(arg.price);
  }
  console.log(arg.name);
}

ユーザー定義型ガードのポイントは各インターフェースに共通のプロパティ名を持たせることです。
またvscodeでは自動補完によるサポートのおかげで、if文内シングルクォート(’)またはダブルクォート(")をタイプした時点でプロパティ名typeに対する値(personかbook)どちらかを推測して表示してくれるため、タイポによるミスがなくなります。

Discussion