Typescript型ガード(Object編)
Typescriptに触れた最初のころから「型ガード」という言葉は知っていましたが、なんとなくで利用していました。
最近になって汎用的な型ガードの使い方を見つけたので、備忘録としてブログに残します。
型ガードって
型ガード=ある値が特定の型であることを保証するものです。
特定の型の場合は○○を、そうでなければ××のように制御したい時ってありますよね?
型ガードはこの制御を助けます。
Objectの判定
まずはよくあるユースケースは、その値が〇〇型かどうかを判定するケースです。
例えば下記のPerson型の例で考えてみましょう。
type Person = {
name: string;
age: number;
};
観察すると、
- string型の値を持つnameキーをもつこと
- number型の値を持つageキーをもつこと
- nameキーとageキー以外のキーは持たないこと
がPerson型であると言えそうですね。
これをチェックする関数(型ガード)を作成してみましょう。
const isPerson = (val: unknown): val is Person => {
if (typeof val !== "object" || val === null) {
return false;
}
const obj = val as Record<string, unknown>;
const keys = Object.keys(obj);
if (keys.length !== 2 || !keys.includes("name") || !keys.includes("age")) {
return false;
}
if (typeof obj.name !== "string") {
return false;
}
if (typeof obj.age !== "number") {
return false;
}
return true;
;
こんな感じでしょうか。コードを読む限り特に難しいポイントはありませんが、個人的にいくつかポイントがあるのでそれぞれについてまとめます。
引数と元り値の型
const isPerson = (val: unknown): val is Person =>
まず引数について、どんな値でも受け取ることができるunknown
が良いのではないかと考えています。any
もありますが、any
よりもunknown
のほうが型安全だし、何より「any
は使うな!」と刷り込まれているので絶対に使いません。というのは半分冗談ですが、unknown
であればany
と違ってメソッドを呼び出すことができないという特性があります。こういった何を受け取るかわからないケースで、メソッドを暗黙的に呼び出せなくする点はunknown
の優秀な点だと思います。
戻り値の型は、型ガードの場合is
を使って表現します。
val === nullをチェックする理由
私も最近型ガードを実装していて気がついたのですが、nullにtypeofをするとobjectになります。
console.log(typeof null); //object
どうやらJavaScriptのバグのようですね。
もしこの仕様(バグ)がなければ、typeof val !== "object"
のみで済むのですが、わざわざnull
を判定するのはこういった事情があります。
keys.length !== 2
これは上記のnameキーとageキー以外のキーは持たないこと
に対応します。
型ガードを実装していて、それぞれのプロパティの型のチェックをする実装は忘れなさそうですが、それ以外のプロパティを持たないことは漏れそうな気がします。
個人的な備忘録として、このブログにも残しておきます。
さいごに
他にも型ガードは色々なケースで利用されますので、型の判定に関する知識をこれからもつけていきたいと思いました。
参考
Discussion