☝️

【TypeScript】この中のどれかの型(ユニオン型)

に公開

ユニオン型とは?

ユニオン型とは簡単に言うと、「この中のどれかの型」というのを表現できるものです。
通常は、

type Hoge = {
  value: string
}

というようにvalueにはstring型しか許容していません。number型を入れようものなら怒られます。
しかし、ユニオン型ではこのように書けます。

type Moge = {
  value: string | number
}

valueにはstring型またはnumber型のどちらかが入るということです。

書き方は「|」(パイプ記号)で区切るだけです。

使い方の例

どんな時に使うの?と思った方に使い方の例を紹介します。

基本的なユニオン型

以下はボタンのサイズをユニオン型にして、"sm"と"md"以外を受け付けない例です。

type ButtonProps = {
  size: "sm" | "md"
  text: string
  disabled: boolean
}

export function Button({ size, text, disabled }: ButtonProps) {
  let sizeClass = ""

  switch(size) {
    case "sm":
      sizeClass = "max-w-[200px] w-full"
      break
    case "md":
      sizeClass = "max-w-[320px] w-full"
      break
    default:
      break
  }

  return (
    <button className={`${sizeClass}`} disabled={disabled}>{text}</button>
  )
}

不要な部分は省いていますが、これにより
"sm"を指定した時は、max-width: 200px;
"md"を指定した時は、max-width: 320px;
となります。

判別可能なユニオン型

以下は「判別可能なユニオン型」と言われる書き方です。

type CardProps =
 | {
      type: "A"
      contents: string
    }
 | {
      type: "B"
      contents: string[]
    }

export function Card({ type, contents }: CardProps) {
  switch (type) {
    case "A":
      return <p>{contents}</p>
    case "B":
      return (
        <ul>
          {contents.map((content, index) => (
            <li key={`list-${index}`}>{content}</li>
          ))}
        </ul>
      }
    default:
      return null
  }
}

typeが"A"の時は、文字列が入り、
typeが"B"の時は、文字列の配列が入ります。
これによりTypeScriptが型を自動で判別してくれるので、安全に分岐処理ができます。
このような書き方を「判別可能なユニオン型」と呼びます。

注意点

ユニオン型はinterfaceで直接定義できません。
基本的にtypeで定義する必要があります。
interfaceを使用している場合は以下のような書き方になります。

interface CardA {
  contents: string
}

interface CardB {
  contents: string[]
}

type CardProps = CardA | CardB;

まとめ

ユニオン型は複数の型のいずれかを取れる型です。柔軟性を持たせつつも、型安全性を保つことができます。
ユニオン型を活用することで、柔軟かつ安全なコンポーネント設計が可能になるので適宜使用していくといいでしょう。

Discussion