Unioni discriminate per le varianti dei componenti
Modelli le props delle varianti con unioni discriminate, così TypeScript impone combinazioni di props valide.
Unioni discriminate per le varianti dei componenti è una lezione React Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento React Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso React Academy include 4 lezioni in totale.
Il problema delle props variant
Un componente con props opzionali per modalità diverse, ad esempio un pulsante che può essere un link o un pulsante, può ammettere combinazioni di props non valide. TypeScript non può rilevarle senza unioni discriminate.
Che cos'è un'unione discriminata
Un'unione discriminata è un'unione di tipi che condividono un campo di tipo literal comune, detto discriminante. TypeScript restringe il tipo in base al valore di quel campo.
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 vs Link
Rappresenti un componente polimorfico con un'unione discriminata basata su un campo as o variant, così da imporre le props corrette per ogni caso.
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>;
}Varianti del componente Alert
Rappresenti un Alert con dati obbligatori diversi per ogni livello di 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>;
}Narrowing nei gestori degli eventi
Le unioni discriminate funzionano anche con dati guidati dagli eventi: sono ideali per le macchine a stati o per lo stato basato sulle azioni.
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;
}Controlli esaustivi con never
Aggiunga un controllo never nel ramo default per ricevere un errore TypeScript se viene aggiunto un nuovo membro dell'unione ma non viene gestito.
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
}
}Unioni discriminate per le risposte API
Rappresenti le strutture delle risposte API come unioni discriminate, così chi le utilizza può gestire i percorsi di successo e di errore senza ricorrere a cast.
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() };
}Type guard per il narrowing
Utilizzi type guard personalizzati per restringere le unioni negli scenari più complessi, quando il discriminante non può essere verificato con un semplice controllo di uguaglianza.
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
}Evitare l'accumulo di props opzionali
Senza unioni discriminate, i componenti accumulano props opzionali valide solo in determinate combinazioni: il risultato è confuso e privo di tipizzazione. Le unioni discriminate eliminano gli stati impossibili.
// 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 };Comporre le unioni
Utilizzi & (intersezione) per aggiungere props condivise a tutti i membri di un'unione.
type BaseProps = { className?: string; children: React.ReactNode };
type ButtonVariant =
| (BaseProps & { variant: 'primary'; onClick: () => void })
| (BaseProps & { variant: 'link'; href: string });Discriminazione a runtime
React usa il discriminante a runtime per eseguire il rendering dell'interfaccia corretta. TypeScript lo usa in fase di compilazione per imporre l'uso corretto delle props. Entrambi i livelli sono protetti.
Verifica rapida
Che cos'è il discriminante in un'unione discriminata?
Riepilogo
Le unioni discriminate rappresentano componenti con insiemi di props mutuamente esclusivi, condividendo un campo discriminante di tipo literal. Utilizzi never nel ramo default per i controlli esaustivi. Eliminano le combinazioni di props non valide consentite dalle props opzionali, rendendo i componenti autoesplicativi e type-safe.
Domande Frequenti
La lezione «Unioni discriminate per le varianti dei componenti» è gratuita?
Sì — il testo completo di «Unioni discriminate per le varianti dei componenti» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso React Academy, passa a CoddyKit PRO. Il corso React Academy include 4 lezioni in totale.
Cosa imparerò in «Unioni discriminate per le varianti dei componenti»?
Modelli le props delle varianti con unioni discriminate, così TypeScript impone combinazioni di props valide. Eserciti React Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare React Academy?
Non è richiesta alcuna esperienza precedente. React Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.
Quanto tempo richiede la lezione «Unioni discriminate per le varianti dei componenti»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione React Academy?
Sì. Ogni lezione React Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Unioni discriminate per le varianti dei componenti
- Tipi condizionali e mappati in React
- Componenti polimorfici con la prop 'as'
- Form type-safe e contratti delle risposte API