ユニオンタイプを使ったpropsの定義
ユニオン型(|
)を使うと、複数のpropsパターンのうちいずれかを許容できます。異なる型構造を1つのコンポーネントで柔軟に扱いたい場合に便利です。
🎯 例:状態に応じてpropsの型を分岐させる
type LoadingState = {
isLoading: true;
};
type LoadedState = {
isLoading: false;
data: string;
};
type Props = LoadingState | LoadedState;
const DataBlock = (props: Props) => {
if (props.isLoading) {
return
<p>読み込み中...</p>;
}
// propsはこの時点でLoadedStateとして推論される
return
<p>データ: {props.data}</p>;
};
✅ ユニオン型を使うと、条件分岐と組み合わせて型を絞り込む(型ガード)ことが可能です。
🎯 例:表示形式のバリエーションを切り替える
type TextProps = {
type: "text";
content: string;
};
type ImageProps = {
type: "image";
src: string;
alt: string;
};
type Props = TextProps | ImageProps;
const Display = (props: Props) => {
switch (props.type) {
case "text":
return
<p>{props.content}</p>;
case "image":
return <img src={props.src} alt={props.alt} />;
}
};
🧠 type
などの判別可能なプロパティ(discriminated union)を使うことで、TypeScriptが自動で型を推論してくれます。
ベースPropsを継承し、ユニオン部分だけを切り替える
ユニオンタイプをより明確・安全に管理する方法として、共通部分をベース型に定義し、変化する部分だけを派生型で表現するという手法があります。
🎯 例:共通レイアウトを持つ複数タイプの表示コンポーネント
✅ ベース型を定義
type BaseProps = {
title: string;
};
✅ 派生型ごとにユニオン部分を分離
type TextProps = BaseProps & {
type: "text";
content: string;
};
type ImageProps = BaseProps & {
type: "image";
src: string;
alt: string;
};
type Props = TextProps | ImageProps;
✅ コンポーネントで使う
const MediaBlock = (props: Props) => {
return (
<div className="media">
<h2>{props.title}</h2>
{props.type === "text" ? (
<p>{props.content}</p>
) : (
<img src={props.src} alt={props.alt} />
)}
</div>
);
};
✅ なぜこの設計が良いのか?
- 🔁 共通プロパティ(
title
など)を毎回繰り返す必要がない - 🧠 型の拡張がしやすく、保守・再利用にも強い
- 🛡️ 判別可能ユニオンによる型安全な条件分岐が可能
🎯 さらに複雑なバリエーションにも応用可能
type BaseProps = {
id: string;
onSelect: (id: string) => void;
};
type VideoProps = BaseProps & {
type: "video";
url: string;
};
type AudioProps = BaseProps & {
type: "audio";
file: string;
};
type MediaProps = VideoProps | AudioProps;
このように、共通のインターフェース(ベース型)を継承しつつ、typeで分岐できる構造は、UIの構成や状態管理など幅広い場面で役立ちます。