Unions discriminées pour les variantes de composants
Modélisez les propriétés de variantes avec des unions discriminées afin que TypeScript impose les combinaisons de propriétés valides.
Unions discriminées pour les variantes de composants est une leçon React Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage React Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours React Academy comprend 4 leçons au total.
Le problème des propriétés de variante
Un composant doté de propriétés facultatives pour différents modes (par exemple, un bouton qui est soit un lien, soit un bouton) peut accepter des combinaisons de propriétés invalides. TypeScript ne peut pas les détecter sans unions discriminées.
Qu'est-ce qu'une union discriminée ?
Une union discriminée est une union de types qui partagent un champ commun de type littéral (le discriminant). TypeScript restreint le type en fonction de la valeur de ce champ.
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'rectangle'; width: number; height: number };
function area(shape: Shape): number {
if (shape.kind === 'circle') return Math.PI * shape.radius ** 2;
return shape.width * shape.height; // TS knows width/height exist here
}Variante Button ou lien
Modélisez un composant polymorphe avec une union discriminée fondée sur un champ as ou variant, afin d'imposer les propriétés correctes pour chaque cas.
type ButtonProps =
| { as: 'button'; onClick: () => void; disabled?: boolean; children: React.ReactNode }
| { as: 'a'; href: string; target?: string; children: React.ReactNode };
function ActionButton(props: ButtonProps) {
if (props.as === 'button') {
return <button onClick={props.onClick} disabled={props.disabled}>{props.children}</button>;
}
return <a href={props.href} target={props.target}>{props.children}</a>;
}Variantes du composant d'alerte
Modélisez une alerte avec des données obligatoires différentes pour chaque type de gravité.
type AlertProps =
| { type: 'success'; message: string }
| { type: 'error'; message: string; onRetry: () => void }
| { type: 'warning'; message: string; details?: string };
function Alert(props: AlertProps) {
if (props.type === 'error') {
return (
<div className="alert error">
<p>{props.message}</p>
<button onClick={props.onRetry}>Retry</button>
</div>
);
}
return <div className={`alert ${props.type}`}>{props.message}</div>;
}Restriction dans les gestionnaires d'événements
Les unions discriminées fonctionnent aussi avec les données pilotées par les événements — elles sont idéales pour les automates d'état ou les états fondés sur des actions.
type LoadingState<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; error: Error };
function DataView<T>({ state }: { state: LoadingState<T> }) {
if (state.status === 'loading') return <Spinner />;
if (state.status === 'error') return <p>{state.error.message}</p>;
if (state.status === 'success') return <pre>{JSON.stringify(state.data)}</pre>;
return null;
}Vérifications exhaustives avec never
Ajoutez une vérification never dans la branche par défaut pour obtenir une erreur TypeScript si un nouveau membre de l'union est ajouté sans être traité.
function assertNever(x: never): never {
throw new Error('Unhandled case: ' + x);
}
function renderIcon(type: AlertProps['type']) {
switch (type) {
case 'success': return <CheckIcon />;
case 'error': return <XIcon />;
case 'warning': return <WarnIcon />;
default: return assertNever(type); // TS error if a case is missing
}
}Unions discriminées pour les réponses d'API
Modélisez les structures de réponse d'API comme des unions discriminées afin que les appelants traitent les chemins de succès et d'erreur sans conversion de type.
type ApiResult<T> =
| { ok: true; data: T }
| { ok: false; error: string; code: number };
async function fetchUser(id: string): Promise<ApiResult<User>> {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) return { ok: false, error: 'Not found', code: res.status };
return { ok: true, data: await res.json() };
}Gardiens de type pour restreindre les types
Utilisez des gardiens de type personnalisés pour restreindre les unions dans les scénarios plus complexes où le discriminant ne se vérifie pas par une simple égalité.
function isSuccess<T>(result: ApiResult<T>): result is { ok: true; data: T } {
return result.ok === true;
}
const result = await fetchUser('1');
if (isSuccess(result)) {
console.log(result.data.name); // TS knows data exists
}Éviter l'accumulation de propriétés facultatives
Sans unions discriminées, les composants accumulent des propriétés facultatives qui ne sont valides que dans certaines combinaisons — ce qui est déroutant et non typé. Les unions discriminées éliminent les états impossibles.
// Bad: optional prop soup — invalid combos allowed:
interface BadProps {
href?: string;
onClick?: () => void;
disabled?: boolean;
}
// Good: only valid combos via discriminated union:
type GoodProps =
| { as: 'a'; href: string }
| { as: 'button'; onClick: () => void; disabled?: boolean };Composer des unions
Utilisez & (intersection) pour ajouter des propriétés partagées à tous les membres d'une union.
type BaseProps = { className?: string; children: React.ReactNode };
type ButtonVariant =
| (BaseProps & { variant: 'primary'; onClick: () => void })
| (BaseProps & { variant: 'link'; href: string });Discrimination à l'exécution
React utilise le discriminant à l'exécution pour afficher l'interface utilisateur appropriée. TypeScript l'utilise à la compilation pour imposer l'utilisation correcte des propriétés. Les deux niveaux sont protégés.
Vérification rapide
Qu'est-ce que le discriminant dans une union discriminée ?
Récapitulatif
Les unions discriminées modélisent les composants avec des ensembles de propriétés mutuellement exclusifs en partageant un champ discriminant de type littéral. Utilisez never dans la branche par défaut pour effectuer des vérifications exhaustives. Elles éliminent les combinaisons de propriétés invalides autorisées par les propriétés facultatives, ce qui rend les composants explicites et sûrs du point de vue du typage.
Questions Fréquemment Posées
La leçon « Unions discriminées pour les variantes de composants » est-elle gratuite ?
Oui — le texte complet de « Unions discriminées pour les variantes de composants » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours React Academy, passe à CoddyKit PRO. Le cours React Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Unions discriminées pour les variantes de composants » ?
Modélisez les propriétés de variantes avec des unions discriminées afin que TypeScript impose les combinaisons de propriétés valides. Tu pratiques React Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer React Academy ?
Aucune expérience préalable n'est requise. React Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.
Combien de temps prend la leçon « Unions discriminées pour les variantes de composants » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon React Academy ?
Oui. Chaque leçon React Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Unions discriminées pour les variantes de composants
- Types conditionnels et mappés dans React
- Composants polymorphes avec la propriété « as »
- Formulaires sûrs du point de vue des types et contrats de réponses d’API