React avec TypeScript
Maintenant que vous connaissez les bases de TypeScript (vues en Séance 1), voyons comment l'utiliser avec React.
TypeScript est obligatoire pour ce cours
Dans ce cours, vous utiliserez TypeScript avec React.
Pourquoi ? Parce que 90% des projets professionnels React utilisent TypeScript. En apprenant React directement avec TypeScript, vous serez prêts pour le monde professionnel et vos futurs stages.
TypeScript est devenu le standard de l'industrie pour les applications React.
Créer un projet React + TypeScript
Avec Vite (recommandé)
# Template React avec TypeScript
npm create vite@latest mon-app -- --template react-ts
cd mon-app
npm install
npm run dev
Le template react-ts configure automatiquement :
- TypeScript avec compilation rapide
- Les types pour React (
@types/react,@types/react-dom) tsconfig.jsonpré-configuré pour React
Vérification en temps réel
Avec TypeScript, votre éditeur VS Code détecte les erreurs avant même d'exécuter le code. Plus besoin d'attendre de voir une erreur dans le navigateur !
Structure du projet
Différence principale : Extensions de fichiers
JavaScript (React) TypeScript (React)
────────────────── ──────────────────
src/
├── App.jsx → ├── App.tsx
├── main.jsx → ├── main.tsx
└── Button.jsx → └── Button.tsx
.tsx = TypeScript + JSX (au lieu de .jsx)
Fichier de config
Le fichier tsconfig.json est créé automatiquement par Vite. Vous n'avez généralement pas besoin d'y toucher !
Typer les props d'un composant
Props : les paramètres d'un composant
En React, les props (propriétés) sont les données passées à un composant, comme les paramètres d'une fonction. Avec TypeScript, vous définissez explicitement quelles props un composant attend et leur type.
Composant simple
JavaScript :
function Welcome({ name }) {
return <h1>Bonjour, {name} !</h1>;
}
TypeScript - Méthode 1 (type inline) :
function Welcome({ name }: { name: string }) {
return <h1>Bonjour, {name} !</h1>;
}
TypeScript - Méthode 2 (interface, recommandé) :
interface WelcomeProps {
name: string;
}
function Welcome({ name }: WelcomeProps) {
return <h1>Bonjour, {name} !</h1>;
}
Quelle méthode choisir ?
Utilisez interface pour les props !
C'est plus lisible et réutilisable. Les types inline conviennent pour les composants très simples.
Quelle est la méthode recommandée pour typer les props d'un composant React ?
Props avec plusieurs types
interface UserCardProps {
name: string;
age: number;
email: string;
isActive: boolean;
avatar?: string; // ? = optionnel
}
function UserCard({ name, age, email, isActive, avatar }: UserCardProps) {
return (
<div className="user-card">
<h2>{name}</h2>
<p>Âge : {age} ans</p>
<p>Email : {email}</p>
<p>Statut : {isActive ? '🟢 Actif' : '🔴 Inactif'}</p>
{avatar && <img src={avatar} alt={name} />}
</div>
);
}
// Utilisation
<UserCard
name="Alice"
age={25}
email="alice@example.com"
isActive={true}
// avatar est optionnel, on peut l'omettre
/>
Props avec union types
interface ButtonProps {
label: string;
variant: 'primary' | 'secondary' | 'danger'; // Seulement ces 3 valeurs
size: 'small' | 'medium' | 'large';
}
function Button({ label, variant, size }: ButtonProps) {
return (
<button className={`btn-${variant} btn-${size}`}>
{label}
</button>
);
}
// Utilisation
<Button label="Cliquer" variant="primary" size="medium" />
// <Button label="Test" variant="warning" /> // ❌ Erreur: 'warning' n'est pas valide
Props avec valeurs par défaut
interface ButtonProps {
label: string;
variant?: 'primary' | 'secondary';
disabled?: boolean;
}
function Button({
label,
variant = 'primary', // Valeur par défaut
disabled = false
}: ButtonProps) {
return (
<button className={`btn-${variant}`} disabled={disabled}>
{label}
</button>
);
}
Props avec fonctions
Les fonctions passées en props se tapent avec leur signature :
interface SearchBarProps {
onSearch: (query: string) => void; // Fonction avec paramètre
onClear: () => void; // Fonction sans paramètre
}
function SearchBar({ onSearch, onClear }: SearchBarProps) {
const [value, setValue] = useState('');
return (
<div>
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
<button onClick={() => onSearch(value)}>🔍</button>
<button onClick={onClear}>✖️</button>
</div>
);
}
Typer children
Le type pour le contenu JSX enfant est React.ReactNode :
interface CardProps {
title: string;
children: React.ReactNode;
}
function Card({ title, children }: CardProps) {
return (
<div className="card">
<h2>{title}</h2>
<div className="content">
{children}
</div>
</div>
);
}
// Utilisation
<Card title="Mon titre">
<p>Contenu de la carte</p>
<button>Action</button>
</Card>
React.ReactNode
React.ReactNode accepte :
- Chaînes de caractères
- Nombres
- JSX (éléments React)
- Tableaux
nullouundefined- Fragments
C'est le type le plus permissif pour children.
Typer les événements
Pour les événements React, TypeScript fournit des types spécifiques :
function LoginForm() {
// Soumission de formulaire
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
console.log('Formulaire soumis');
};
// Changement d'input
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log('Valeur:', e.target.value);
};
return (
<form onSubmit={handleSubmit}>
<input onChange={handleChange} placeholder="Email" />
<button type="submit">Connexion</button>
</form>
);
}
Laisser TypeScript inférer
Pour les gestionnaires inline, vous n'avez pas besoin de typer :
<input onChange={(e) => console.log(e.target.value)} />
<button onClick={(e) => console.log('Cliqué')}>Cliquer</button>
TypeScript devine automatiquement le type de e.
Typer useState
useState : le hook d'état
useState est le hook React qui permet de gérer l'état local d'un composant. TypeScript peut souvent deviner le type automatiquement, mais parfois vous devez l'indiquer explicitement.
Inférence automatique
import { useState } from 'react';
function Counter() {
// TypeScript devine que count est un number
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
Type explicite (quand nécessaire)
interface User {
id: number;
name: string;
email: string;
}
function UserProfile() {
// State qui peut être User ou null
const [user, setUser] = useState<User | null>(null);
// Tableau vide au départ
const [users, setUsers] = useState<User[]>([]);
return (
<div>
{user ? (
<p>{user.name} - {user.email}</p>
) : (
<p>Aucun utilisateur</p>
)}
</div>
);
}
État avec objet complexe
interface FormData {
name: string;
email: string;
age: number;
subscribe: boolean;
}
function Form() {
const [formData, setFormData] = useState<FormData>({
name: '',
email: '',
age: 0,
subscribe: false
});
const handleChange = (field: keyof FormData, value: string | number | boolean) => {
setFormData({
...formData,
[field]: value
});
};
return (
<form>
<input
value={formData.name}
onChange={(e) => handleChange('name', e.target.value)}
/>
{/* ... */}
</form>
);
}
Quand devez-vous spécifier explicitement le type dans useState ?
Erreurs courantes
Erreur : Property 'X' is missing
// ❌ Prop requise manquante
<Button label="Cliquer" />
// ✅ Ajoutez la prop ou rendez-la optionnelle (?)
<Button label="Cliquer" onClick={() => {}} />
Erreur : Type 'string' is not assignable to type 'number'
// ❌ Type incorrect
<User age="25" />
// ✅ Utilisez le bon type
<User age={25} />
Erreur : Object is possibly 'null'
// ❌ Accès sans vérification
const name = user.name;
// ✅ Optional chaining
const name = user?.name;
Interface vs Type
Pour les props React, utilisez interface (plus lisible) :
// ✅ Recommandé pour les props
interface ButtonProps {
label: string;
onClick: () => void;
}
// ✅ Pour les unions
type Status = 'loading' | 'success' | 'error';
Vous avez vu les détails en Séance 1.
Résumé
Ce que vous savez maintenant
Créer un projet React + TypeScript :
npm create vite@latest mon-app -- --template react-ts
Typer les props avec interface :
interface ButtonProps {
label: string;
onClick: () => void;
disabled?: boolean; // Optionnel avec ?
}
function Button({ label, onClick, disabled = false }: ButtonProps) {
return <button onClick={onClick} disabled={disabled}>{label}</button>;
}
Types React essentiels :
React.ReactNode→ PourchildrenReact.FormEvent→ PouronSubmitReact.ChangeEvent<HTMLInputElement>→ PouronChange
useState avec types :
const [user, setUser] = useState<User | null>(null);
const [users, setUsers] = useState<User[]>([]);
Conventions :
interfacepour les propstypepour les unions ('loading' | 'success')- Fichiers React :
.tsx(TypeScript + JSX)
Ressources complémentaires
React TypeScript Cheatsheet
Guide de référence complet pour React avec TypeScript
DocumentationDocumentation officielle TypeScript
Guide TypeScript pour React
DocumentationTotal TypeScript - React with TypeScript
Tutoriel interactif gratuit par Matt Pocock
TutorielProchaine étape : Passez aux exercices pour mettre en pratique tous les concepts React !