TypeScriptにおける Function Components と React.FC
の比較: 建設的な議論
React と TypeScript が一つのプロジェクトに入ってきました。TypeScript は「型は任せて」と言い、React は「描画は私が担当」と応えます。そしていつしか誰かがこう聞きます。
React.FC
を使うべき?それとも関数に直接型付けすればいい?
合理的な疑問です。一見すると、React.FC
は洗練され公式のように見え、まるでコードに「このコンポーネントを優雅にしましょう」と言ってワインを注いでくれるかのようです。しかし、その表面の下には、現代のTypeScriptではほとんど使われなくなった問題も抱えています。
詳しく見ていきましょう。
2つのスタイル
プレーンな関数コンポーネント
type Props = { title: string };
function MyComponent({ title }: Props) {
return <h1>{title}</h1>;
}
シンプルで明快、わかりやすい。ブラックコーヒーのように無駄がなく、仕事をきっちりこなします。
あるいは、アロー関数が好みなら:
const MyComponent = ({ title }: Props) => {
return <h1>{title}</h1>;
};
どちらも有効で読みやすく、現在のベストプラクティスに合致しています。
React.FC 版
import { FC } from 'react';
type Props = { title: string };
const MyComponent: FC<Props> = ({ title }) => {
return <h1>{title}</h1>;
};
このバージョンはコンポーネントをジェネリック型でラップします。より「公式」らしく見え、TypeScriptのユーティリティ型に触れたばかりなら自然な選択に感じるかもしれません — まるで秘密のクラブに入ったような感覚です。しかし、秘密のクラブには細則があることもあります。
React.FC が実際にしていること
React.FC(React.FunctionComponentの略)は関数コンポーネントを表すヘルパー型です。いくつかのデフォルト動作を提供します:
- children props を常に含む(望んでいてもいなくても)
- 特定のエディタではオートコンプリートが向上することがある
- 関数の戻り値の型をやや明示的にできるが、実際はほとんど重要でない
これらは控えめな利便性で、初期の React + TypeScript では役立っていました。しかし時代は変わり、現在ではそれらの「機能」がむしろ邪魔になることが多いです。
なぜ使われなくなってきたのか
React.FC は例えるならTypeScript界のカーゴパンツ — ポケットはたくさんあるけどほとんど使われない。
- 暗黙の children
すべてのコンポーネントが children prop を持つことになり、不要でも入ります。このため、型があるから子要素が有効と思い込みバグになることがあります。(結論:必ずしも有効とは限りません)
- ジェネリクスと相性が悪い
コンポーネントでジェネリック型を使う際、React.FC はむしろ複雑にしがちで、TypeScriptも扱いにくくなります。
- 冗長でわかりにくい
const MyComponent: FC<Props>
と書くのは、単に Props に直接型付けするより長くて、わかりづらいこともあります。
- もう必要ない
React.FC を使った当初の理由(エディタ支援やJSX推論)は、TypeScriptの進化でほぼ解決されています。かつての実用的な回避策が古いスタイルになりました。
並べて比較
特徴 | function Component() | const Component: FC |
---|---|---|
childrenを含むか? | 宣言した場合のみ | 常に含まれる |
ジェネリック対応 | スムーズ | 手間がかかる |
冗長さ | 最小限 | かなり多い |
エディタサポート | 十分 | 特定のケースでやや優れる |
推奨されるか? | はい | もう推奨されない |
推奨されるアプローチ
コミュニティのコンセンサスはシンプルです:propsに直接型付けしましょう。childrenを受け入れたいなら明示的に指定し、そうでなければ無いままでいい。未来の自分が感謝する素直さです。
type Props = {
title: string;
children?: React.ReactNode;
};
const MyComponent = ({ title, children }: Props) => (
<div>
<h1>{title}</h1>
{children}
</div>
);
明示的でメンテしやすく、コンポーネントでchildrenを扱っていないのに扱う振りをしません。
React.FC が今でも意味を持つことは?
稀にあります。レガシーコードベースでReact.FCが多用されている場合、コードの整合性を保つために使い続けるほうが良いこともあります。また、子要素の型を気にせず手早くコンポーネントをモックアップしたい時にはショートカットとして有効です。
しかし、一般的にはそれらは例外であり、ルールを証明するものです。
おわりに
React.FC が間違っているわけではありません。ただ、もはや必要ではないのです。現代のTypeScriptではReactコンポーネントの型付けがよりシンプルで予測可能になりました。
次回FCを使う時は、一度立ち止まって、それが付加価値を生むのか、ただ余計な層を重ねているだけかを考えましょう。多くの場合、シンプルな型付き関数のほうがずっと使いやすいです。
ソフトウェアも人生も— 明快さは賢さに勝る。そして驚きが少なければ後悔も少ないのです。