propsの型で楽する

props の型を定義するとき、

  • 組み込み要素の props を引き継ぐ
  • 不適切な props 値を設定できないようにする

際に参考になりそうな事を記載します。

組み込み要素の props を自身のコンポーネントに加える

htmlの要素が持つ pops を自身が作成するコンポーネントでも使うとき、ひとつひとつ定義すると大変なことになりますよね。
そういうときは、JSX.IntrinsicElements が便利です。

例えば、自身が作成するコンポーネントで button を使っていて、button が持つ props を受け取れることを定義したいときは、

type MyButtonProps = JSX.IntrinsicElements['button'];

とすればOKです。自身のコンポーネント用に expanded: boolean という props があるなら、

type MyButtonProps = {
  expanded: boolean;
} & JSX.IntrinsicElements['button'];

という形で定義できます。

props に設定が間違っている事が分かるようにする

props の定義で、組み合わせできない props の値が設定されても、エラーで気が付けるようにできます。
少し長いですが以下の様な形です。

import React from 'react';

type BaseProps = {
  label: string;
}

type OrderedProps = {
  listType: 'ordered';
  listStyle: 'decimal' | 'cjk-decimal' | 'upper-roman';
} & BaseProps
  & JSX.IntrinsicElements['ol'];

type UnorderedProps = {
  listType: 'unordered';
  listStyle: 'none' | 'disc' | 'circle' | 'square';
} & BaseProps
  & JSX.IntrinsicElements['ul'];

type Props = OrderedProps | UnorderedProps;

export default function MyList(props: Props) {
  const {
    label,
    listStyle,
    children,
    ...otherProps
  } = props;

  let listEl = <></>;
  if (props.listType === 'ordered') {
    listEl = <ol
      style={{ listStyleType: listStyle }}
      {...(otherProps as JSX.IntrinsicElements['ol'])}
    >{children}</ol>;
  }
  if (props.listType === 'unordered') {
    listEl = <ul
      style={{ listStyleType: listStyle }}
      {...(otherProps as JSX.IntrinsicElements['ul'])}
    >{children}</ul>;
  }
  return (
    <div>
      <div>{label}</div>
      {listEl}
    </div>
  );
}

listType が

  • ‘ordered’ なら、listStyle に使えるのは ‘decimal’, ‘cjk-decimal’, ‘upper-roman’
  • ‘unordered’ なら、listStyle に使えるのは ‘none’, ‘disc’, ‘circle’, ‘square’

となるので、違っている場合は指摘されます。

Visual Studio Code 上なら、
listType が ‘ordered’ なら、
listStyle に ‘none’ は使えないので、
MyList に波線が付いて、間違っていることが分かります。

type として OrderedProps と UnorderedProps を定義して Props はそのどちらかとすることで、できない組み合わせを設定されたときでも間違いに気づけます。

type Props = OrderedProps | UnorderedProps;

VSCode で props のサジェストも追随してくれると更に楽なんですが、そこまで判断はされませんでした。

コメント