Reactコンポーネントのprops設計、どうしてる？3つの代表パターンを比較

# はじめに

React + TypeScriptで開発をしていると、コンポーネントのprops型の書き方に迷うことはありませんか？

この記事では、典型的な `Profile` コンポーネントを例に、**props型の書き方3パターンを比較し、それぞれのメリット・デメリットと使い分け方**を紹介します。

**👤 前提：`Profile`コンポーネントが受け取るprops**

```ts
{
  name: string;
  age: number;
  avatarUrl: string;
  bio: string;
  onClick: () => void;
}
```

# 1. propsをまるごと受け取る

```tsx
export default function Profile(props: {
  name: string;
  age: number;
  avatarUrl: string;
  bio: string;
  onClick: () => void;
}) {
  return (
    <div onClick={props.onClick}>
      <img src={props.avatarUrl} alt={props.name} />
      <h2>{props.name}</h2>
      <p>{props.bio} - {props.age}歳</p>
    </div>
  );
}
```

✅ メリット

* その場でサクッと書ける
* 型定義が近くて文脈がすぐわかる

❌ デメリット

* `props.` を毎回書くのが冗長
* 型を再利用できない
* propsが多くなると視認性が悪化

# 2. 分割代入 + inlineで型定義

```tsx
export default function Profile({
  name,
  age,
  avatarUrl,
  bio,
  onClick,
}: {
  name: string;
  age: number;
  avatarUrl: string;
  bio: string;
  onClick: () => void;
}) {
  return (
    <div onClick={onClick}>
      <img src={avatarUrl} alt={name} />
      <h2>{name}</h2>
      <p>{bio} - {age}歳</p>
    </div>
  );
}
```

✅ メリット

* 分割代入でコードがすっきり
* propsが少ないときに最も簡潔
* `props.` を書かなくて済む

❌ デメリット

* 型の再利用ができない
* 関数の宣言と型定義が一体になっていて視認性が低い
* propsが多くなると引数が長くなって読みにくい

# 3. props型を定義して `React.FC` を使う✨

```tsx
import React from "react";

interface ProfileProps {
  name: string;
  age: number;
  avatarUrl: string;
  bio: string;
  onClick: () => void;
  children?: React.ReactNode; // ← React18以降、必要なら明示する
}

const Profile: React.FC<ProfileProps> = ({
  name,
  age,
  avatarUrl,
  bio,
  onClick,
}) => {
  return (
    <div onClick={onClick}>
      <img src={avatarUrl} alt={name} />
      <h2>{name}</h2>
      <p>{bio} - {age}歳</p>
    </div>
  );
};

export default Profile;
```

✅ メリット

* 型を他の場所でも再利用できる
* 読みやすく、保守しやすい
* 型を他コンポーネント・テスト・Storybookなどで再利用できる
* propsが多くてもスッキリ書ける
* 補完やJSDocコメントもつけやすい

❌ デメリット

* propsが少ないときはやや冗長に感じる


> 💡 補足
React 17以前では React.FC に children が暗黙的に含まれていましたが、React 18以降では含まれません。children を使用するには、自分で children?: React.ReactNode を型定義に追加しましょう。

@honey32 さん、ご指摘ありがとうございます！

# React.FCを使うべき？

**✅ こんな時に便利**

* 戻り値が明確になることで読みやすくなる
* 「これはReactの関数コンポーネントですよ」とパッと見で伝わる

**⚠️ 避けるケースもある**

* パフォーマンスチューニングなどで細かいpropsの扱いが必要な場合

**🧠 使い分けのまとめ**

| ケース                         | おすすめの書き方           |
| --------------------------- | ------------------ |
| propsが少ない（1〜2個）             | パターン①または②          |
| propsが中程度（3〜5個）             | パターン②（可読性重視）       |
| propsが多い／型を再利用したい           | パターン③ + `React.FC` |
| コンポーネントに `children` も受け取りたい | パターン③が最適           |

# 補足：`type` vs `interface`

どちらでもOKですが、単純なpropsの型なら `type` の方が柔軟です：

```ts
type LocaleLayoutProps = {
  children: React.ReactNode;
  params: Promise<{ lang: "en" | "ja" }>;
};
```

ただし、**継承したい・マージしたい**ときは `interface` の方が便利なので使い分けましょう。

# 補足：JSX.ElementとReact.ReactElement

| 型名                   | 説明                              | よく使う場面        |
| -------------------- | ------------------------------- | ------------- |
| `JSX.Element`        | JSX構文から返される型（Reactの戻り値として自然）    | 関数コンポーネントの戻り値 |
| `React.ReactElement` | より汎用的。render関数やchildrenなどにも使われる | 汎用的な型指定をしたいとき |

ほとんどの場合、関数コンポーネントの戻り値は `JSX.Element` を使えばOKです。

**🧠 JSX.Elementを使うメリット**

* エディタ上での補完が効きやすい
* TypeScriptが自動でJSX記法を型推論するので、明示しておくと保守性が上がる
* 複数の開発者が関わるプロジェクトで**意図が明確**になる（"この関数はReactのUIを返す"）


# おわりに

React + TypeScriptにおいて、**propsの型の書き方は「開発効率」「保守性」「読みやすさ」に直結**します。

書き方に正解はありませんが、「今のコンポーネントがどのくらいの規模で、将来的にどう変化するか？」を意識して使い分けることで、コードの品質がグッと上がります。