🛡️

Typescript型ガード(Object編)

2024/12/17に公開

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キー以外のキーは持たないことに対応します。
型ガードを実装していて、それぞれのプロパティの型のチェックをする実装は忘れなさそうですが、それ以外のプロパティを持たないことは漏れそうな気がします。
個人的な備忘録として、このブログにも残しておきます。

さいごに

他にも型ガードは色々なケースで利用されますので、型の判定に関する知識をこれからもつけていきたいと思いました。

参考

https://qiita.com/shimi7o/items/da9db1c82164534c55b9

Discussion