【React】【TypeScript】ComponentProps で props に関わる型定義を楽にする

 ComponentProps は React で用意されている型の一つで次の様に定義されています。

// node_modules/@types/react/index.d.ts
// React.ComponentProps
    /**
     * NOTE: prefer ComponentPropsWithRef, if the ref is forwarded,
     * or ComponentPropsWithoutRef when refs are not supported.
     */
    type ComponentProps<T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> =
        T extends JSXElementConstructor<infer P>
            ? P
            : T extends keyof JSX.IntrinsicElements
                ? JSX.IntrinsicElements[T]
                : {};

 ぱっと見、何が書いてあるかわかりません。IDE のジャンプ機能を使えばわからなくもないですがやはり辛いです。これは使用例を見てそういうものである、と納得するのが使いやすいです。使用例は次です。

/*** MessageLogComponent.tsx ***/
// あるコンポーネントに使われるコンポーネント
import React from 'react';

/**
 * このファイルのコンポーネントの props の型定義
 */
type MessageLogProps = {
  messages: Array<{
    time: string;
    msg: string;
  }>;
};
/**
 * MessageLogProps を使うコンポーネント
 */
export default function MessageLogComponent(props: MessageLogProps): JSX.Element {
  // コンポーネントの中身
}


/*** App.tsx ***/
// MessageLogComponent を使うコンポーネント
import React, { ComponentProps } from 'react';
import MessageLogComponent from './MessageLogComponent';

/**
 * このファイルのコンポーネントの state の型定義
 */
type AppState = {
  // これで messageLog の型 === メッセージログの props の型となります。
  messageLog: ComponentProps<typeof MessageLogComponent>;
};
/**
 * MessageLogComponent などを使うルートコンポーネント
 */
export default class App extends React.Component<never, AppState> {
  /**
   * 初期化
   * @param props
   */
  constructor(props: never) {
    super(props);
    this.state = {
      messageLog: {
        messages: [
          {
            msg: '',
            time: '',
          },
        ],
      },
    };
  }

  /**
   * 描画
   */
  render(): JSX.Element {
    // 対象のコンポーネントの props と同じ型の state 部を展開して props を全て満たします
    return <MessageLogComponent {...this.state.messageLog} />;
  }
}

 上記例の様に、ComponentProps を用いることによってあるコンポーネントを元としてそのコンポーネントの props の型を取得できます。これを使うことで多数のコンポーネントを管理することになるコンポーネントの state 定義が非常に楽になります。特筆すべき点として、 ComponentProps の対象コンポーネントの props の型が変わった場合、自動で呼び出し側の型定義も変更される点があります。これによってコンポーネントの props 型定義を変えたことによって連動して変更しなければいけない部分の変更を漏らすことが非常に少なくなります。
 TypeScript らしく補完も機能します。多少オブジェクトの規模が大きくなった程度で混乱することもなくなります。

 困ったことにこの手の便利そうな型定義は公式ドキュメント( reactjs.org, ja.reactjs.org)で見つけられませんでした。自分の初見はライブラリの実装を読んでいた時です。こういったものを調べるには react typescript cheatsheet の様な便利機能の例を探していくのがよさそうです。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG