TypeScriptで条件別に必須パラメーターを変更する方法
この記事では、Reactコンポーネントでの引数に型定義を行う際に、特定のパラメータの有無で必須となるパラメータを設定する方法を簡単にまとめています。
広告ここから
広告ここまで
目次
この記事では、Reactコンポーネントでの引数に型定義を行う際に、特定のパラメータの有無で必須となるパラメータを設定する方法を簡単にまとめています。
作りたかったもの
ナビゲーション要素でありがちな「今いるページと同じパスならクリックできないリンク要素」を作ろうとしていました。マークアップについては共通化したいため、コンポーネントの引数によって振る舞いを変えるようにします。
要件を箇条書きするとだいたいこうなります。
- linkで使うときは、
href
を指定したい - そうじゃないときは、
span
/button
どっち使うか指定するas
propsを指定したい href
/as
は同時に使えないようにしたい
理想系としては、IDEでこのようなエラーが出てほしいと考えています。
Baseの型定義と、使い方ごとの型定義を用意する
いろいろ調べたところ、次のような型をまず用意することにしました。リンクとして機能させる際の型定義と、ただのHTML要素として扱う際の型定義の2つを作っています。ポイントとしては、使って欲しくない型をnever | undefined
になるように定義した事です。
type BaseBottomNavigationItemProps = {
label: string
icon: ReactNode
}
type LinkBottomNavigationItemProps = BaseBottomNavigationItemProps & {
href?: string
as?: never;
}
type ButtonBottomNavigationItemProps = BaseBottomNavigationItemProps & {
as?: 'span' | 'button'
href?: never;
}
Reactコンポーネントの定義としては、Unionで定義します。
export const BottomNavigationItem: FC<BottomNavigationItemProps | LinkButtomNavigationItemProps> = ({ label, icon, href, as = 'span' }) => {...}
このようにすることで、期待した通りの型エラーが発生します。
今の所の理解
- 条件分岐的な型定義をしたい場合は、それぞれの型を定義した上でUnionする
- 使って欲しくない値については、
never | undefined
として設定する
まだまだあまりTypeScriptには詳しくないですが、また何か試したときは整理も兼ねて記事化します。