第30章:Propsに「?」をつける
―― 「あってもいいし、なくてもいい」データを表現しよう ✨
1️⃣ この章のゴール 🎯
この章がおわるころには、こんなことができるようになります👇
- 「このPropsは あってもいいし、なくてもいい」を型で表現できる 💡
name?: stringが何を意味しているか説明できる ✍️- オプショナルなPropsを受け取るコンポーネントを自分で書ける 🧩
undefinedが来ても安全に表示できる書き方がわかる ✅
2️⃣ おさらい:ふつうの(必須の)Props 🧠
まずは今までのPropsをちょっと思い出しましょ。
たとえば、こんな自己紹介コンポーネントがあるとします👇
type ProfileProps = {
name: string; // ← 絶対に必要なProps(必須)
};
function Profile({ name }: ProfileProps) {
return <p>{name} さん、こんにちは!</p>;
}
export function App() {
return (
<div>
{/* ✅ OK:必須の name を渡している */}
<Profile name="さくら" />
{/* ❌ エラー:name を渡してない */}
{/* <Profile /> */}
</div>
);
}
name: stringは「nameというプロパティが 必ずある し、値はstring」という意味です。- なので、
<Profile />のようにnameを渡さないと TypeScript が怒ります😡
「いやいや、name がなくても動いてほしいときもあるんだけど?」
→ そういうときに登場するのが ? をつけたオプショナルProps です🌟
3️⃣ name?: string ってどういう意味?🤔
オプショナルPropsの例はこちら👇
type ProfileProps = {
name?: string; // ← "?" がついている
};
function Profile({ name }: ProfileProps) {
return <p>{name} さん、こんにちは!</p>;
}
name?: string はざっくりいうと…
「
nameが あるかもしれないし、ないかもしれない。 もしあるならstringだよ」
という意味です。
TypeScript的には、ほぼこういうイメージです👇
// イメージ(実際のコンパイル結果とは少し違うけど、考え方として)
type ProfileProps = {
// "name がある場合は string、そもそもプロパティがないかもしれない"
name: string | undefined;
};
つまり:
-
親コンポーネントから見て:
nameを渡してもいいし、渡さなくてもいい
-
子コンポーネントから見て:
nameはstringのときもあるし、undefinedのときもある
4️⃣ Mermaidでイメージ図を見てみよう 🧠✨
オプショナルPropsのイメージを図にしてみます👇
title:ぜったい渡さなきゃダメ(必須)subtitle?:あってもOK/なくてもOK(オプショナル)
こんな感じで、「優先順位の高いものは必須」「あったらうれしいものはオプショナル」 みたいに分けることができます🌈
5️⃣ 実例:サブタイトルは「なくてもOK」なカード 💳
よくあるパターンとして、「タイトルは必須だけど、サブタイトルはあってもなくてもいい」というカードを作ってみましょう。
✅ 型定義(Props)
type InfoCardProps = {
title: string; // 必須
subtitle?: string; // オプショナル(あってもなくてもOK)
};
✅ コンポーネント本体
subtitle がない(=undefined)ときは、そもそもサブタイトル部分を表示しないようにしてみます。
function InfoCard({ title, subtitle }: InfoCardProps) {
return (
<div style={{ border: "1px solid #ccc", padding: "12px", borderRadius: "8px" }}>
<h2>{title}</h2>
{/* subtitle があるときだけ表示する */}
{subtitle && <p style={{ color: "#666" }}>{subtitle}</p>}
</div>
);
}
✅ 親コンポーネントから呼び出し
export function App() {
return (
<div style={{ padding: "16px", display: "flex", gap: "16px" }}>
{/* ✅ subtitle あり */}
<InfoCard
title="JavaScript勉強会"
subtitle="毎週火曜日・みんなでゆるくコードを書く会 ✏️"
/>
{/* ✅ subtitle なし(渡さなくてOK) */}
<InfoCard title="React入門ノート" />
</div>
);
}
ポイント ✨
subtitle?: stringにしたことで、<InfoCard title="..." />のようにsubtitleを渡さなくてもエラーになりません。- コンポーネントの中では
subtitleはstring | undefinedとして扱われるので、subtitle && ...のように「あるときだけ表示」する書き方がよく使われます👌
6️⃣ どうやって安全に表示する??? と デフォルト値 🎀
オプショナルPropsは undefined の可能性があるので、
そのまま使うとちょっと危ない ときがあります。
パターン①:??(null合体演算子)でデフォルト文字列を出す
type GreetingProps = {
name?: string;
};
function Greeting({ name }: GreetingProps) {
// name が undefined のときは "ゲスト" を使う
const displayName = name ?? "ゲスト";
return <p>{displayName} さん、ようこそ〜 👋</p>;
}
??は「左がnullかundefinedのときだけ右側を使う」という演算子です。nameが"さくら"→"さくら"nameがundefined→"ゲスト"
パターン②:分割代入のところでデフォルト値をつける
もっと短く書くならこちらもおすすめです👇
type GreetingProps = {
name?: string;
};
function Greeting({ name = "ゲスト" }: GreetingProps) {
// ここに来た時点で name は「string」確定
return <p>{name} さん、ようこそ〜 🥰</p>;
}
-
name = "ゲスト"と書いたことで、nameが渡されなかった →"ゲスト"が入るname="ひな"が渡された →"ひな"が入る
-
コンポーネントの中では
nameの型はもはやstringだけになっていて扱いやすいです✨
7️⃣ よくある「?」との違いを整理しよう 🧩
TypeScriptやJavaScriptでは、いろんなところに ? が登場します。
ざっくり整理すると👇
| 記法 | 例 | 意味 |
|---|---|---|
プロパティの ? | name?: string | あってもいいし、なくてもいい(オプショナル) |
引数の ? | fn(name?: string) | その引数を省略してもOK |
| オプショナルチェーン | user?.name | user が null/undefined なら止める |
三項演算子の ? | cond ? A : B | if文みたいな分岐 |
この章で扱っているのは 「プロパティの ?」=オプショナルProps です 🎓
8️⃣ ミニ練習:ニックネームはあってもなくてもOKな挨拶 💌
🧪 お題
UserGreeting というコンポーネントを作ってみましょう。
-
Props:
fullName(フルネーム):必須(string)nickname(ニックネーム):オプショナル(string)
-
表示ルール:
nicknameがあるとき →"{nickname}({fullName})さん、こんにちは〜 💕"nicknameがないとき →"{fullName} さん、こんにちは〜 ☺️"
VSCodeで UserGreeting.tsx を作るイメージで書いてみてください ✏️
✅ サンプル解答(見たいときだけ見てね)
type UserGreetingProps = {
fullName: string; // 必須
nickname?: string; // オプショナル
};
export function UserGreeting({ fullName, nickname }: UserGreetingProps) {
// 「表示用の名前」を決める
const display =
nickname !== undefined
? `${nickname}(${fullName})`
: fullName;
return <p>{display} さん、こんにちは〜 🌸</p>;
}
// どこかのファイルから呼び出す例
export function App() {
return (
<div style={{ padding: "16px", display: "flex", flexDirection: "column", gap: "8px" }}>
{/* ニックネームあり */}
<UserGreeting fullName="山田 花子" nickname="はな" />
{/* ニックネームなし */}
<UserGreeting fullName="佐藤 愛" />
</div>
);
}
ポイント 💡
-
nickname?: stringとすることで、nicknameを渡してもいいし、渡さなくてもOKにできた 🎉
-
中で
nickname !== undefined ? ... : ...のように分岐することで、- どちらのパターンも安全に処理できる ✅
9️⃣ まとめ:この章でおぼえてほしいこと 🐣
-
name?: stringは「あってもいいし、なくてもいいname」という意味 ✨ -
オプショナルなPropsは、あったら便利だけど必須ではない情報 に使うとGOOD 👍
-
中身を使うときは:
subtitle && ...で「あるときだけ表示」したりname ?? "ゲスト"や{ name = "ゲスト" }のように デフォルト値をつけると安全&ラクになります 💪
-
いろんな
?があるけど、この章の主役は プロパティの?(オプショナルProps) 💕
次の章では、実際のプロジェクトの中で「オプショナルProps」をどう組み合わせると便利か、 さらに手を動かしながら慣れていきましょうね〜 🎉💻🌈