【React×TypeScript】propsの型を条件分岐させる

React

propsの型を条件によって分岐させる方法を2つ記録しておきます🙋‍♀️
※コンポーネントのサンプルコードに関しては、あくまでコードの書き方を示すものとして見てください。

1つのpropの値で分岐させる

あるpropの値を元に型を分岐させるやり方です。
以下だと、「typebuttonの場合はButtonPropsを参照」「typelinkの場合はLinkPropsを参照」する仕組みになっています。

type ButtonProps = {
  type: 'button'
  onClick: MouseEventHandler<HTMLButtonElement>
}

type LinkProps = { type: 'link'; href: string }

type Props = {
  children: ReactNode
} & (ButtonProps | LinkProps)

const MyButton = (props: Props) => {
  if (props.type === 'button') {
    return <button onClick={props.onClick}>{props.children}</button>
  }

  if (props.type === 'link') {
    return <a href={props.href}>{props.children}</a>
  }

  return null
}

もちろんstring型に限らず、他の型での分岐も可能です。
以下はboolean型のtrue/falseかによって切り替える一例です。

type Props =
  | { isLoggedIn: true; name: string; rank: 'gold' | 'silver' }
  | { isLoggedIn: false }

一方のpropが存在する場合は、他方のpropを受け取らない

「値を持たない」ことを意味するnever型を使用します。
以下の例では、「prop isRequiredが渡された場合はprop isOptionalの受け取り禁止、逆にprop isOptionalが渡された場合はprop isRequiredの受け取り禁止」をしています。

type Props = {
  children: ReactNode
} & (
  | {
      isRequired?: boolean
      isOptional?: never
    }
  | {
      isRequired?: never
      isOptional?: boolean
    }
)

const MyLabel = ({ children, isRequired, isOptional }: Props) => {
  return (
    <label>
      {children}
      {isRequired && <span>Required</span>}
      {isOptional && <span>Optional</span>}
    </label>
  )
}

2つ紹介しましたが、どちらの方法が良いかは各コンポーネントによって変わると思うので、状況によって使い分けてください🌱

タイトルとURLをコピーしました