TypeScript + React 実践
TypeScript は React 開発に完全な型サポートを提供し、コードの信頼性を向上させます。
TypeScript を使うことで、React コンポーネント、Props、State などすべてに完全な型チェックが行われ、実行時エラーを減らすことができます。
React チュートリアルを見る:https://www.example.com/vue3/react-tutorial.html
SVG 図:React + TypeScript 開発フロー
なぜ React で TypeScript を使うのか
React のコンポーネント化開発では、Props、State、Context などのデータフローが大量に発生します。
型定義がないと、データの発生源や構造を追跡するのが難しく、実行時エラーが発生しやすくなります。
TypeScript は React に完全な型システムを提供します。コンポーネントの Props には型チェック、useState には型推論、イベント処理には型ヒントがあります。
データフロー:React のデータフロー(Props、State、Context)にはすべて型定義が必要で、TypeScript はデータフローの型安全性を保証できます。
プロジェクトの作成
最新のスキャフォールドを使って TypeScript をサポートする React プロジェクトを作成します。
初期化
npx create-react-app my-app --template typescript
# または Vite を使用(推奨・より高速)
npm create vite@latest my-app -- --template react-ts
推奨:Vite は現在最も推奨される React ビルドツールで、高速で開発体験も優れています。
コンポーネント型
React.FC 型を使って関数コンポーネントを定義します。
src/components/Button.tsx
// ボタンコンポーネントの Props 型を定義
interface ButtonProps {
text: string; // ボタンのテキスト(必須)
onClick: () => void; // クリックコールバック(必須)
disabled?: boolean; // 無効かどうか(オプション、デフォルト false)
variant?: "primary" | "secondary"; // ボタンのバリアント(オプション)
}
// React.FC で関数コンポーネントの型を定義
const Button: React.FC<ButtonProps> = ({
text,
onClick,
disabled = false,
variant = "primary"
}) => {
return (
<button
className={`btn btn-${variant}`}
onClick={onClick}
disabled={disabled}
>
{text}
</button>
);
};
export default Button;
実行結果:
Button 组件渲染成功
React.FC:これは React 関数コンポーネントの型で、children、propTypes などの組み込み型が含まれます。
Props 型
コンポーネントの Props インターフェースを定義し、子コンポーネントにデータを渡します。
src/components/UserCard.tsx
// ユーザー型を定義
interface User {
id: number; // ユーザー ID
name: string; // ユーザー名
email: string; // メールアドレス
avatar?: string; // アバター(オプション)
}
// ユーザーカードコンポーネントの Props を定義
interface UserCardProps {
user: User; // ユーザーオブジェクト(必須)
onEdit: (user: User) => void; // 編集コールバック
onDelete: (id: number) => void; // 削除コールバック
}
const UserCard: React.FC<UserCardProps> = ({ user, onEdit, onDelete }) => {
return (
<div className="user-card">
{user.avatar && <img src={user.avatar} alt={user.name} />}
<h3>{user.name}</h3>
<p>{user.email}</p>
<button onClick={() => onEdit(user)}>編集</button>
<button onClick={() => onDelete(user.id)}>削除</button>
</div>
);
};
export default UserCard;
型の受け渡し:Props を通じて型を渡すことで、コンポーネントツリー全体のデータ型を一致させます。
useState 型
useState に型パラメータを指定して、状態の型が正しいことを保証します。
src/components/Counter.tsx
const Counter: React.FC = () => {
// 基本型:明示的に number 型を指定
const [count, setCount] = useState<number>(0);
// オブジェクト型:オブジェクト型を指定
const [user, setUser] = useState<{ name: string; age: number }>({
name: "Alice",
age: 25
});
return (
<div>
<p>カウント: {count}</p>
<button onClick={() => setCount(c => c + 1)}>+1</button>
<button onClick={() => setCount(c => c - 1)}>-1</button>
<p>ユーザー: {user.name}, {user.age}</p>
<button onClick={() => setUser({ ...user, age: user.age + 1 })}>
年齢+1
</button>
</div>
);
};
export default Counter;
実行結果:
Counter 组件渲染成功
ジェネリック型パラメータ:useState<T> の T は状態の型であり、初期値を指定すると TypeScript が自動的に推論できます。
useEffect 型
useEffect にも完全な型サポートがあります。
src/components/DataFetcher.tsx
// ユーザー型を定義
interface User {
id: number;
name: string;
}
const DataFetcher: React.FC = () => {
// ユーザーリストの状態
const [users, setUsers] = useState<User[]>([]);
// ロード状態
const [loading, setLoading] = useState<boolean>(true);
// エラー状態
const [error, setError] = useState<string | null>(null);
useEffect(() => {
// データ取得をシミュレート
fetch("/api/users")
.then(res => res.json())
.then(data => {
setUsers(data);
setLoading(false);
})
.catch(err => {
setError(err.message);
setLoading(false);
});
}, []); // 空の依存配列:コンポーネントのマウント時に一度だけ実行
if (loading) return <div>読み込み中...</div>;
if (error) return <div>エラー: {error}</div>;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
export default DataFetcher;
依存配列:useEffect の第2引数は依存配列です。TypeScript はコールバック内で使用する変数がすべて配列内で宣言されているかをチェックします。
イベント処理
React イベントには専用の型定義があります。
src/components/Form.tsx
const Form: React.FC = () => {
// 文字列型の状態
const [name, setName] = useState<string>("");
// フォーム送信イベント処理
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault(); // フォームのデフォルト送信を防ぐ
console.log("送信:", name);
};
// 入力欄の変更イベント処理
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setName(e.target.value);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="名前を入力"
/>
<button type="submit">送信</button>
</form>
);
};
export default Form;
実行結果:
Form 组件渲染成功
イベント型:React は FormEvent、ChangeEvent、MouseEvent など、すべての DOM イベントに型を提供しています。
注意事項
- React.FC:推奨:完全な型サポートが得られます
- Props インターフェース:各コンポーネントに Props 型を定義する
- useState ジェネリック:複雑な型は明示的に指定する必要がある
- イベント型:React 提供のイベント型を使用する
ベストプラクティス:型定義とコンポーネントを同じファイルに置くか、types ディレクトリにまとめて管理します。
まとめ
TypeScript は React の開発体験を大幅に向上させました。
- React.FC:React 関数コンポーネントの標準型
- Props:interface を使ってコンポーネントの属性を定義する
- useState:ジェネリックパラメータを使って状態の型を指定する
- useEffect:完全な型サポート
- イベント:React のイベント型を使用して any を避ける
その他の拡張提案:新規プロジェクトでは TypeScript を直接使用すると、実行時エラーを大幅に減らせます。