propsの型を条件によって分岐させる方法を2つ記録しておきます🙋♀️
※コンポーネントのサンプルコードに関しては、あくまでコードの書き方を示すものとして見てください。
1つのpropの値で分岐させる
あるpropの値を元に型を分岐させるやり方です。
以下だと、「type
がbutton
の場合はButtonProps
を参照」「type
がlink
の場合は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つ紹介しましたが、どちらの方法が良いかは各コンポーネントによって変わると思うので、状況によって使い分けてください🌱