【実務・中級編】 TypeScriptのTypeエイリアスによるProps定義 – React実践ガイド

ReactにおけるProps定義の極意:interfaceか、typeか。現場で迷わないための境界線

現場でコードレビューをしていると、必ずと言っていいほど議論になるのが「Propsの定義に `interface` を使うべきか、`type` を使うべきか」という問題だ。

結論から言えば、「どちらでも動く。しかし、意図をコードに刻むべきだ」というのが私の答えだ。Reactのコンポーネント設計において、型定義は単なるエラーチェックの道具ではない。それは、そのコンポーネントが「何者であるか」を宣言するドキュメントそのものだからだ。

今日は、中級者から一歩先へ進むために、実務で自信を持って使い分けるための指針を授けよう。

—

1. `interface` vs `type`:現場での現実的な使い分け

まず、技術的な差異を整理しておこう。結論、TypeScript 4.x以降、この二つの性能差はほぼ無に等しい。だが、Reactの現場では以下の基準で使い分けるのが「プロの所作」だ。

interface を選ぶべき場面

  • 公開用コンポーネント(ライブラリ作成など): `interface` は拡張性(Declaration Merging)がある。外部から型を後付けで拡張できるため、APIの柔軟性が求められる場面で重宝する。
  • オブジェクトの構造を定義するとき: オブジェクトの「形」を定義するなら、直感的で読みやすい。

type を選ぶべき場面

  • 複雑な合成型: `Union型`(`’success’ | ‘error’`)や `Intersection型`(`A & B`)、`Mapped Types` を使う場合。これらは `interface` では表現できないか、非常に書きにくい。
  • コンポーネントのProps定義: 現代的なReact開発では、Propsの定義には `type` を推奨するチームが増えている。なぜなら、Propsは「ただのデータの固まり」であり、継承(`extends`)による複雑化を避けるほうが、長期的なメンテコストが低いからだ。

—

2. 実務で「刺さる」Props定義のベストプラクティス

現場で最も嫌われるのは、「何でもあり」の Props 定義だ。特に `children` の扱いや、オプショナルな Props の扱いが雑だと、コンポーネントの挙動が予測不能になる。

以下のコードは、私が実際に現場のコードベースで標準化している「きれいな Props 定義」のテンプレートだ。

import { ReactNode } from ‘react’;

// 1. 複雑な条件分岐が必要な場合は type を採用
type ButtonVariant = ‘primary’ | ‘secondary’ | ‘danger’;

// 2. Props定義は読みやすさを最優先
type ButtonProps = {
label: string;
variant?: ButtonVariant; // オプショナルな値は明示的に
disabled?: boolean;
// 3. childrenの型は ReactNode を使うのが現代の標準
// React.FC を使わず、あえて戻り値型を推論させるのが今のトレンド
children?: ReactNode;
onClick?: (event: React.MouseEvent) => void;
};

/

  • ボタンコンポーネント
  • @param label – ボタンの表示テキスト
  • @param variant – スタイルのバリエーション

/
export const Button = ({
label,
variant = ‘primary’, // デフォルト引数で安全性を担保
disabled = false,
children,
onClick,
}: ButtonProps) => {
return (

);
};

なぜ `React.FC` を使わないのか?

かつては `const MyComponent: React.FC = …` と書くのが一般的だったが、現在は避ける傾向にある。理由は単純で、`React.FC` を使うと `children` が暗黙的に含まれてしまうからだ。「このコンポーネントは `children` を受け取らないはず」という意図が型レベルで隠蔽されるのは、大規模開発ではバグの温床になる。明示的に書く。これこそが信頼を生む。

—

3. ブラウザの裏側で何が起きているか(エンジニアの視点)

TypeScriptで型を書くとき、私たちは「型安全」という贅沢な恩恵を受けているが、ブラウザ(V8エンジンなど)にとって、これらの型定義はコンパイル時に「消滅」する。

重要なので繰り返すが、TypeScriptの型はランタイムには一切存在しない。

だからこそ、型定義で頑張りすぎる必要はない。「実行時にどう振る舞うか」を意識し、型はあくまで「開発者がミスをしないためのガードレール」と割り切るのが賢い。例えば、実行時に `Props` の値が本当に期待通りか不安な場合は、`Zod` のようなバリデーションライブラリを型と併用するのが、シニアエンジニアの現場での戦い方だ。

—

最後に:完璧を目指さず、一貫性を目指せ

最後に一つだけアドバイスさせてくれ。
「どちらの書き方が正しいか?」と悩む時間は、正直言って一番の無駄だ。チーム内で「Propsは `type` で書く」「`interface` で書く」というルールを統一し、それを守り続けることこそが、コードの品質を左右する。

Reactは自由だ。その自由を活かすも殺すも、君の型定義一つにかかっている。次回のコードレビューでは、「なぜこの定義にしたのか?」という意図を言語化してみてほしい。それができれば、君はもう一段階、スペシャリストに近づいているはずだ。

また何か壁にぶつかったら、いつでも聞きに来るといい。現場の戦場でお待ちしている。

コメント

タイトルとURLをコピーしました