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には詳しくないですが、また何か試したときは整理も兼ねて記事化します。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark