こんにちは!Reactの学習、楽しく進めていますか?
「画面のパーツを組み合わせてアプリを作る」というワクワク感の一方で、TypeScriptと一緒に使い始めた途端、見たこともないエラーの赤波線に直面して「ぐぬぬ……」となった経験、ありませんか?
大丈夫ですよ。その戸惑いは、あなたがしっかりと現実のコードに向き合っている証拠です。誰もが一度は通る道ですから、安心してくださいね。
さて今回は、React 18以降で地味に(でも確実に)私たちの頭を悩ませる`React.PropsWithChildren`の仕様変更と、それに対する一番スマートな処方箋について、おしゃべりするようにお話ししていきたいと思います。
—
1. 「画面の中に別の中身を包み込む」というお馴染みの仕組み
Reactでコンポーネントを作っていると、こんな風に、タグの中に別の要素やテキストを挟み込みたくなることがよくありますよね。
こんにちは、私のなかにいるよ!
身近な例えで言うなら、「中身が自由に変えられる透明なギフトボックス」みたいなものです。箱(`MyBox`)を用意しておけば、中身にぬいぐるみを入れてもいいし、手紙を入れてもいい。
この「箱の中に突っ込まれる中身たち」のことを、Reactの世界では親しみを込めて `children`(チルドレン) と呼びます。
TypeScriptを使うときの「ちょっとした面倒くささ」
「この箱の中身は、どんなものが入ってきてもいいですよ〜」とTypeScriptに教えてあげるために、私たちは型(プロパティの設計図)を書いてあげる必要があります。
昔(React 17以前)の私たちは、こんな風に書いていました。
// 昔の書き方:これで「children持っててもいいよ」という意味になっていました
type MyBoxProps = {
title: string;
};
const MyBox: React.FC
return (
{title}
{children} {/ ここに中身が表示される /}
);
};
「あれ? 別に`children`の型をわざわざ書き足してないのに、エラーにならないぞ?」と思いました?
そうなんです。昔は、`React.FC`という「コンポーネントの型」を使うと、勝手に裏側で「`children`があっても怒らないでおいてあげるね」という魔法(おせっかい)をかけてくれていたんです。
—
2. React 18で何が変わったの?「おせっかい」の卒業
月日は流れ、Reactはバージョン18へと進化しました。
このReact 18の型定義(@types/react)のアップデートで、大きな方針転換が行われました。
それは一言で言うと、「勝手に裏側で魔法をかけるの、やめました!」 という宣言です。
> 【ここがポイント】
> React 18以降、`React.FC`を使っても、`children`は自動的にはついてこなくなりました。
「えっ、じゃあReact 18でさっきのコードを書いたらどうなるの?」
はい、TypeScriptから容赦なくこんな怒りのメッセージが飛んできちゃいます。
> 「おいおい、`children`なんてプロパティ、`MyBoxProps`の設計図に書いてないぞ!」
この仕様変更に気づかず、「あれ、バージョンアップしたら急にエラーが出るようになったぞ……?」と、世界中のフロントエンドエンジニアが冷や汗をかいたのは、ここだけの秘密です(笑)。
—
3. 救世主登場:`React.PropsWithChildren` との出会い
「じゃあ、毎回自分で`children`の型を書かなきゃいけないの? めんどくさいな……」
そんな私たちのために、Reactチームが用意してくれた公式の便利グッズが、今回主役の `React.PropsWithChildren` です。
これは、「手元にある自分の設計図(今回の場合は`MyBoxProps`)に、`children`の型を合体させてパワーアップさせてくれる魔法の糊(のり)」のようなものです。
使ってみると、こんなにスッキリします。
import React from ‘react’;
// 1. 自分が本当に欲しいプロパティだけを定義する
type MyBoxProps = {
title: string;
};
// 2. PropsWithChildrenで包み込む!これで children が自動で合体します
const MyBox: React.FC
return (
{title}
);
};
これなら、「自分で`children?: React.ReactNode`って書くの忘れちゃった!」という凡ミスを防ぎつつ、スマートにコードが書けますよね。
—
4. チーフアーキテクトがこっそり教える、現場の「リアルな推奨プラクティス」
さて、ここからが現場の裏話です。
「おっ、じゃあ`React.PropsWithChildren`を使いまくれば完璧だな!」と思ったそこのあなた。実は、実務の現場では、もう一段階進んだ「もっとシンプルで確実な方法」が好まれる傾向にあります。
それは何かというと……
> `React.FC`を使うのをやめて、普通の関数として書き、`children`の型を自分で明示的に(`ReactNode`として)書く方法 です。
百聞は一見にしかず、実際のコードを見てみましょう。
import React, { ReactNode } from ‘react’;
// 自分だけの設計図の中に、最初から children を含めちゃいます
type MyBoxProps = {
title: string;
children: ReactNode; // 「画面に描画できるものなら何でもOK!」という意味
};
// React.FC を使わず、普通のTypeScriptの関数として書く
export const MyBox = ({ title, children }: MyBoxProps) => {
return (
{title}
);
};
なぜ、この書き方が現場で愛されているの?
1. コードが直感的で読みやすい
わざわざ`React.PropsWithChildren<...>`という長い名前をインポートしたり思い出したりする必要がありません。設計図(Type)を見た瞬間に「あ、このコンポーネントは`title`と中身の`children`を受け取るんだな」と一目で分かります。
2. `React.FC`特有の「落とし穴」を回避できる
実は`React.FC`には、「何も子要素を取らないはずのコンポーネントにも、暗黙的に`children`が通ってしまう(空のタグが許されてしまう)」という、ちょっとしたおせっかいな挙動(※近年のバージョンで改善されつつありますが)があります。普通の関数として書くことで、コンポーネントの挙動を完全に自分の手でコントロールできるようになります。
—
まとめ
今回の話をギュッとまとめますね。
- React 18以降では、`React.FC`を使っても`children`は自動でついてこなくなった!
- 楽をしたい時は `React.PropsWithChildren
` を使えば、一瞬で`children`の型を合体させられる。 - でも、現場のチーフアーキテクトとしては、自分で `children: ReactNode` と明示的に型を定義する書き方 の方が、見通しが良くておすすめ!
型エラーが出ると「うっ……」と身構えてしまうかもしれませんが、TypeScriptの赤波線は、あなたのコードの安全を守ってくれる「優しいお節介な警備員さん」のようなものです。
「あ、ここに`children`の型を教えてあげればいいんだな」と仕組みさえ分かってしまえば、もう怖いものはありません。
ぜひ、あなたのプロジェクトでも試してみてくださいね。それでは、快適なReactライフを!

コメント