判別可能なUnion型
はじめに
今回の判別可能な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
ちょうど探していた情報で助かりました。ありがとうございます。