mizkog-logo

Web制作の備忘録

HomeZenn

Type Guard(型ガード)の色々な例

Type Guard(型ガード)とは

型の絞り込み。
型が複数考えられる場合にType Guardで型を特定していくこと。

tyepofを使ったType Guard

以下のように、typeof用いることで型の絞り込みが出来る。

export const foo = (value: string | number | boolean) => {
  if(typeof value === "string") {
    return value;
    // value: string
  }
  if(typeof value === "number") {
    return value;
    // value: number
  }
  return value;
  // value: boolean
};


JavaScriptや演算子を使ったType Guard

JavaScriptを使ったType Guard

Array.isArray()のようなJavaScriptのメソッドを用いて、型の絞り込みが出来る。

export const foo = (value: string | string[]) => {
  if(Array.isArray(value)) {
    return value;
    // value: string[]
  }
  return value;
  // value: string
};


演算子を使ったType Guard

例えば以下のように論理否定演算子を用いて、valueがfalsyだった場合にif文の中を返すことで、
undefinedの可能性を消去できる。

export const foo = (value?: string) => {
  if(!value) {
    return value;
    // value: string | undefined
  }
  return value;
  // value: string
};

こちらは頻出で、React等を使っていて上からpropsが渡ってきた時にpropsの値がオプショナルだった場合に可能性を消去する。そして、下のreturn文でコンポーネントを記述する。のような場面で出てくる。

ちなみに、if文内はvalue: string | undefinedとなっているが、
空文字に!を付けるとtruthyとなる=条件分岐に入りstringの可能性が残る。ということ。
実際は以下のように、nullやただのreturnにする。

export const foo = (value?: string) => {
  if(!value) {
    return null;
  }
  return value;
};

or

export const foo = (value?: string) => {
  if(!value) {
    return;
  }
  return value;
};


in演算子を使ったType Guard

以下のように"nickname" in valueとすることで、valueにnicknameがあるかどうかで、
型の絞り込みが出来る。

type UserA = { name: string };
type UserB = { name: string; nickname: string };

export const foo = (value: UserA | UserB) => {
  if("nickname" in value) {
    return value;
    // value: UserB
  }
  return value;
  // value: UserA
};


タグ付きUnion Types(Discriminated Union,Taggrd Union)を使ったType Guard

以下のようにUserAもUserBも同じようなプロパティを持っている時に、
タグ付きUnion Typesを用いて型の絞り込みが出来る。

type UserA = { name: string; lang: "ja" };
type UserB = { name: string; lang: "en" };

export const foo = (value: UserA | UserB) => {
  if(value.lang === "ja") {
    return value;
    // value: UserA
  }
  return value;
  // value: UserB
};

実際にはAdminと一般ユーザーを分けたりするようなtype,kind,id等をよく見るが、特に決まりはなくいろんなプロパティがTagとして使われる。

switch文を使ったType Guard

以下のように、switch文を用いて型の絞り込みが出来る。

type UserA = { name: string; lang: "ja" };
type UserB = { name: string; lang: "en" };
type UserC = { name: string; lang: "fr" };

export const foo = (value: UserA | UserB | UserC) => {
  switch (value.lang) {
    case "ja": {
      return value;
    }
    case "en": {
      return value;
    }
    case "fr": {
      return value;
    }
    default: {
      throw Error("lang is not defined!");
    }
  }
};