【TypeScript】Union型の型ガード・型の絞り込み方法まとめ

JavaScript

型ガード(Type Guard)とはif文やcase文をはじめとした条件分岐で変数の型を判別し、ブロック内の変数の型を絞り込む機能のことをいいます。

型の絞り込みをすることでブロック内の変数の型が特定されるため、型のキャスト(型を明示して変換すること)が不要になります。

今回は複数の型をもつ可能性のあるUnion型の変数の型を絞り込む方法について紹介します。

typeofを利用する

typeofはプリミティブ型を判別する型ガード演算子です。
プリミティブ型のUnion型はtypeofで型を絞り込めます。

const convert = (value: string | number): string => {
  if (typeof value === 'string') {
    return value.toUpperCase(); // string型と推論される
  } else {
    return value.toString(); // number型と推論される
  }
}

console.log(convert('hoge'))
// "HOGE"

console.log(convert(123))
// "123"

typeofの詳細解説は【TypeScript】型ガード(タイプガード)の概要。typeofとinstanceofの利用例で紹介しています。

instanceofを利用する

instanceofはクラスを判別する型ガード演算子です。
クラスのUnion型はinstanceofでクラスを絞り込めます。

class Cat {
  name: string
  meow: string
  constructor(name: string, meow: string) {
    this.name = name
    this.meow = meow
  }
}

class Duck {
  name: string
  quack: string
  constructor(name: string, quack: string) {
    this.name = name
    this.quack = quack
  }
}

type Animal = Cat | Duck

const say = (animal: Animal): string => {
  if (animal instanceof Cat) {
    return animal.meow // Catクラスと推定される
  } else {
    return animal.quack // Duckクラスと推定される
  }
}


const tama = new Cat('Tama', 'meow!!meow!!')
const shiro = new Duck('Shiro', 'quack!!quack!!')

console.log(say(tama))
// "meow!!meow!!"

console.log(say(shiro))
// "quack!!quack!!"

instanceofの詳細解説は【TypeScript】型ガード(タイプガード)の概要。typeofとinstanceofの利用例で紹介しています。

ユーザー定義型ガードを利用する

ユーザー定義型ガードとは型ガードの役割をはたす関数のことです。
ユーザー定義型ガードの戻り値は引数 is 型(型述語、Type Predicate)です。

戻り値が引数 is Tの場合、「trueなら引数は型T、falseなら型Tではない」という挙動になります。

const isString = (value: string | number): value is string => {
  return typeof value === "string";
}

const convert = (value: string | number): string => {
  if (isString(value)) {
    return value.toUpperCase(); // string型と推論される
  } else {
    return value.toString(); // number型と推論される
  }
}

console.log(convert('hoge'))
// "HOGE"

console.log(convert(123))
// "123"

なお、ユーザー定義型ガードおよびis(Type Predicate)の詳細解説はTypeScpirtのis(Type Predicate)を使ってユーザー定義型ガードを実装するで紹介しています。

inを利用する

inを利用することでオブジェクトのプロパティの有無を判定できます。
この機能を活用するとinで型の絞り込みができます。

typeofが利用できない独自定義の型ではinによる型の絞り込みが有効です。

type Cat = {
  name: string;
  meow: string;
}

type Duck = {
  name: string;
  quack: string;
}

type Animal = Cat | Duck;

const say = (animal: Animal): string => {
  if ('meow' in animal) {
    return animal.meow // Cat型と推論される
  } else {
    return animal.quack // Duck型と推論される
  }
}

const tama: Cat = {
  name: 'Tama',
  meow: "meow!!meow!!"
}

const shiro: Duck = {
  name: 'Shiro',
  quack: "quack!!quack!!"
}

console.log(say(tama))
// "meow!!meow!!"

console.log(say(shiro))
// "quack!!quack!!"

なお、inを利用した型の絞り込みの詳細解説は【TypeScript】inを利用して型の絞り込みを行う方法で紹介しています。

さいごに

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!

参考記事