こんにちは。TypeScriptの世界へようこそ。
現場でコードを書いていて、「あれ、ここのProps定義、毎回同じことを書いていないか?」とか「`?`(オプショナル)をつけた途端に、値の扱いが面倒になった……」なんて経験はありませんか?
TypeScriptの型システムは、単なる「エラーを防ぐためのガードレール」ではありません。「設計の意思をコードに刻み込むための設計図」です。今日は、ReactコンポーネントのProps設計を通じて、`interface`を使った「DRY(Don’t Repeat Yourself)」かつ堅牢な設計術をマスターしていきましょう。
—
1. なぜ「型エイリアス」ではなく「Interface」なのか?
TypeScriptには `type`(型エイリアス)と `interface` という二つの強力なツールがあります。結論から言えば、ReactのProps定義には `interface` を推奨します。
理由はシンプル。`interface` は「拡張性」と「宣言的結合」に優れているからです。
// インターフェースの宣言
interface ButtonProps {
label: string;
onClick: () => void;
}
// あとから同じ名前で宣言すると、自動的に合体(宣言マージ)される
interface ButtonProps {
disabled?: boolean; // オプショナルプロパティの追加
}
// 結果:ButtonPropsは 3つのプロパティを持つことになる
この「後から継ぎ足せる」性質は、ライブラリ開発や大規模なコンポーネント設計において、非常に強力な武器になります。
—
2. 継承で「Propsの重複」を撲滅する
コンポーネントを作っていると、「アイコンボタン」や「プライマリボタン」など、似たようなPropsを持つコンポーネントが量産されますよね。ここで `extends` を使ってベースの型を継承しましょう。
// ベースとなる共通の型
interface BaseProps {
className?: string; // オプショナル: あってもなくても良い
style?: React.CSSProperties;
}
// BasePropsを継承した、より具体的なProps
interface ButtonProps extends BaseProps {
label: string;
variant: ‘primary’ | ‘secondary’;
onClick: () => void;
}
ここがポイント:
`className?: string` のように `?` をつけることで、「呼び出し側は必須で渡さなくてもいい」という自由度を与えています。これをオプショナルプロパティと呼びます。
—
3. 陥りやすい罠:「undefined」との付き合い方
初心者が一番苦戦するのが、オプショナルにしたプロパティを扱うときです。
const MyComponent = ({ label, className }: ButtonProps) => {
// classNameは undefined かもしれないので、そのままでは使えない場合がある
return
;
};
初心者のうちは、「なぜ `className` が空かもしれないと怒られるの?」と不思議に思うでしょう。これは、TypeScriptが「実行時の予期せぬクラッシュ」を未然に防ぐために、値が存在しない可能性を厳格にチェックしているからです。
これを解決する最も美しい方法は「デフォルト引数」を使うことです。
// 分割代入のデフォルト値を使うと、型定義と実行時が綺麗に一致する
const MyComponent = ({ label, className = ‘btn-default’ }: ButtonProps) => {
return ;
};
これだけで、「未定義ならデフォルト値をセットする」というロジックが、型定義の意図と完璧に同期します。
—
4. 現場で差がつく:型を絞り込む「ユニオン型」の活用
単に「文字列」を受け取るだけでなく、許容する値を制限するのもプロの技です。
interface CardProps {
// 文字列なら何でもいいわけではなく、特定の3種類に限定する
size: ‘small’ | ‘medium’ | ‘large’;
title: string;
}
このように型を絞り込むと、エディタが「次に何を書けばいいか」をサジェストしてくれます。「型定義=ドキュメント」となる瞬間です。これこそが、TypeScriptを導入する最大のメリットと言えるでしょう。
—
本日のまとめ:TypeScriptを掌握するコツ
1. `interface` を使おう: 拡張性が高く、将来的な変更にも強いコードが書けます。
2. `extends` でDRYに: 共通部分はベース型にまとめ、差分だけを継承しましょう。
3. オプショナル `?` は「自由」と「責任」: 渡さなくても良いという自由を与える代わりに、受け取る側で `undefined` のケア(デフォルト値など)をする責任を持つ。
4. リテラル型で縛る: `string` と書くのをやめて、`’primary’ | ‘secondary’` と具体的に書きましょう。
ここをクリアできれば、あなたの書くコンポーネントは、自分だけでなく、将来の自分やチームメンバーにとっても「最高に読みやすく、壊れにくい」ものになります。
さあ、次はどんなコンポーネントを型で守ってみましょうか? ぜひ手を動かして、この強力な型システムを遊び尽くしてくださいね!