Reactで学ぶPropsとStateの型管理!型安全に組み合わせてバグを減らす方法(TypeScript)
生徒
「ReactってPropsとStateが大事って聞きました。でもTypeScriptだと型が増えて混乱します…」
先生
「Propsは外から受け取る情報、Stateは自分の中で変わる情報です。型をうまく組み合わせると、間違いを早めに止められます。」
生徒
「Propsの型とStateの型って、別々に書くんですか?同じ形のデータが出てきたらどうしますか?」
先生
「同じ形なら共通の型を作って使い回します。親子コンポーネントで値を渡したり、更新の関数を渡したりするのも、型で安全にできますよ。」
生徒
「親から渡すPropsと、子のStateを一緒に安全に扱うコツを知りたいです!」
1. PropsとStateの違いを超やさしく整理
Propsは、コンポーネントが外から受け取る情報です。たとえば「表示するタイトル」「最初の数」「ボタンの文字」など、親から子へ渡すメモのようなものです。
Stateは、コンポーネントの中で変化する情報です。たとえば「カウントの現在値」「入力欄の文字」「開いているかどうか」など、画面の動きに合わせて変わる値です。
TypeScriptでは、PropsとStateそれぞれに型を付けられます。型は「この箱には何が入るか」を決めるルールなので、Reactのバグ予防にとても役立ちます。
2. まずはPropsの型を作る:親から渡す情報を安全にする
Propsは「受け取る側」が型を決めます。受け取り側で「nameは文字」「initialCountは数字」のように定義すると、親が間違った値を渡したときに気づけます。
import React, { useState } from "react";
type CounterProps = {
label: string;
initialCount: number;
};
function Counter(props: CounterProps) {
const [count, setCount] = useState(props.initialCount);
return (
{props.label}:{count}
);
}
export default function App() {
return (
);
}
ここではPropsの型をCounterPropsとして作り、子コンポーネントの引数で受け取っています。Stateの初期値にPropsを使うことで、「最初の数は親が決める」「増えた数は子が管理する」という役割分担ができます。
3. PropsとStateが同じ形なら共通の型を作る
Reactでは、親から渡すデータと子のStateが「同じ形」になる場面がよくあります。たとえばユーザー情報やTodoのように、項目が決まっているデータです。
このとき、Props用とState用に別々の型を作ると、ズレが起きやすくなります。そこで、共通の型を1つ作って、PropsにもStateにも使うのがコツです。
import React, { useState } from "react";
type User = {
id: number;
name: string;
};
type ProfileProps = {
user: User;
};
function Profile(props: ProfileProps) {
const [currentUser, setCurrentUser] = useState(props.user);
return (
ID:{currentUser.id}
名前:{currentUser.name}
);
}
export default function App() {
return ;
}
ここではUserという型を1つ作り、PropsのuserにもStateのcurrentUserにも使っています。こうすると「PropsとStateで形が違う」という事故を防ぎやすくなります。
4. PropsからStateを作るときの注意点:初期値として使うのが基本
PropsをStateの初期値にするのは便利ですが、初心者がつまずきやすいポイントもあります。Stateは「自分の中のメモ」なので、一度作った後はPropsが変わっても自動で追いかけないことがあります。
そのため、まずは「Propsは初期値として一回だけ使う」と覚えると安全です。たとえば「初期表示の文字」「最初のカウント」「初期選択」などです。
もし「親が変えた値を子にも反映したい」なら、Stateを持たずにPropsをそのまま表示する、または親にStateを持たせる設計が分かりやすいです。TypeScriptの型管理でも、Stateの持ち場所を整理するとコードが読みやすくなります。
5. 親のStateを子に渡す:valueと更新関数をPropsで渡す
Reactでよくあるのが、親がStateを持ち、子は表示と操作だけを担当する形です。親のStateを子へPropsで渡し、子は「更新して」と親にお願いするための関数もPropsで受け取ります。
ここがPropsとStateの組み合わせで一番大切な場面です。TypeScriptでは「値の型」と「更新関数の型」をセットでそろえると、型安全になります。
import React, { useState } from "react";
type InputProps = {
value: string;
onChangeValue: (nextValue: string) => void;
};
function TextInput(props: InputProps) {
return (
入力:{props.value}
);
}
export default function App() {
const [text, setText] = useState("");
return (
);
}
ここでは親のStateがtextで、子はvalueとして受け取ります。更新はonChangeValueで親に伝えます。関数の引数をstringにしているので、子が間違った型で更新しようとすると止められます。
6. 型管理のコツ:Propsの型は「受け取り口」をはっきりさせる
Propsの型は、コンポーネントの「受け取り口」を説明するものです。受け取り口がはっきりすると、親は正しい値だけを渡せるようになります。
特に、次のような情報は型で決めておくと混乱が減ります。
- 文字列か数値か真偽値かを明確にする
- オブジェクトや配列は共通の型を作って使い回す
- 更新関数は「何を受け取って何をするか」を型で表す
この考え方を押さえると、PropsとStateを組み合わせたときでも、Reactの画面が崩れにくくなります。
7. 初心者が覚えておくと楽になる型の言葉
ここで出てきたTypeScriptの言葉を、短く整理します。
- 型:値の種類を決めるルール。文字、数字、真偽、オブジェクトなど。
- 型定義:オブジェクトの形を決める説明書。たとえば名前と年齢をセットにする。
- union型:どれか一つという意味。たとえばデータか空のどちらか。
- コールバック:あとで呼び出すために渡す関数。更新関数をPropsで渡すのが典型。
PropsとStateを型安全にしたいときは、難しい技よりも「同じ形を同じ型で使う」「値と更新をセットでそろえる」という基本が効きます。ReactとTypeScriptの組み合わせは、初心者でも安心して画面を作りやすくなるのが強みです。
8. optionalなPropsとStateの組み合わせ:あるかもしれない値を安全にする
Reactでは「渡すときもあるし、渡さないときもある」Propsが出てきます。これをTypeScriptではoptionalと呼び、型の中で?を付けて表します。
たとえば「表示タイトルはあれば出す」「なければ固定の文字にする」といったケースです。Propsが省略できると、親のコードが書きやすくなりますが、子は「入っていない可能性」を忘れないようにします。
ここで役立つのが、初期値や代わりの値です。Propsがないときは別の文字を使う、と決めておくと、画面が安定します。Stateを作る場合も、最初から空文字を入れておけば、nullチェックが増えにくくなります。
9. PropsとStateをつなぐ設計:どこにStateを置くかで型が整理される
PropsとStateの型管理が難しく感じる原因は、「誰がその値を持つのか」があいまいになりやすいからです。Reactでは、値を持つ場所を決めると型も自然に決まります。
基本の考え方は次の通りです。
- 画面の複数の場所で同じ値を使うなら、親がStateを持って子へPropsで渡す
- そのコンポーネントの中だけで完結するなら、そのコンポーネントがStateを持つ
- 子から親へ変更を伝えたいなら、更新関数をPropsで渡す
このルールで整理すると、Propsは「受け取るだけ」、Stateは「自分で変えるだけ」という役割がはっきりします。TypeScriptの型も、Props用とState用で迷いにくくなります。
10. 実務でよくある組み合わせ:リスト表示と選択状態を型安全にする
Reactでよく作る画面に「一覧を表示して、クリックした項目を選択する」というものがあります。ここでは、一覧データをPropsで受け取り、選択中のidをStateで持つのが分かりやすいです。
大事なのは、一覧の要素の型と、選択状態の型を同じルールでそろえることです。たとえば一覧のidが数字なら、選択中idも数字にします。idの型がズレると、比較がうまくいかず、選択表示が壊れやすくなります。
import React, { useState } from "react";
type Item = {
id: number;
name: string;
};
type ItemListProps = {
items: Item[];
};
function ItemList(props: ItemListProps) {
const [selectedId, setSelectedId] = useState(null);
return (
選択中:{selectedId === null ? "なし" : selectedId}
{props.items.map((item) => (
))}
);
}
export default function App() {
return (
);
}
ここでは、一覧の型をItemにして、Propsのitemsに使っています。選択中は「まだ選んでいない」状態があるので、Stateはnumber | nullにしています。こうしておくと、未選択のときに無理やり数字として扱ってしまうミスを減らせます。
11. 迷ったらこの形:Propsの型とStateの型を近くに置いて読みやすくする
初心者のうちは、型がいろいろな場所に散らばると混乱しやすくなります。まずは「そのコンポーネントで使う型は近くに置く」と覚えると読みやすくなります。
たとえば、コンポーネントの上にPropsの型、次にStateで使う型、という順番に置くと、どんなデータを扱う部品なのかが一目で分かります。Reactのコンポーネントは小さな部品の集合なので、部品ごとに説明書をそろえると、あとから見返したときに助かります。
PropsとStateを組み合わせた型管理は、「難しいテクニック」より「分かりやすい整理」が効きます。共通の型を作って使い回し、値と更新をペアで扱う。この基本だけでも、TypeScriptでのReact開発はぐっと安全になります。