I tipi distribuiti (Distributive Types) sono una caratteristica di TypeScript che si manifesta quando si lavora con i tipi condizionali (T extends U ? X : Y). Quando la variabile di tipo a sinistra di extends è un'unione (union), TypeScript distribuisce la condizione su ciascun elemento dell'unione.
Esempio:
// "Test<A> | Test<B> | Test<C>" type Test<T> = T extends string ? () => string : () => number; type Result = Test<'A' | 'B' | 'C'>;
Qui Result si distribuisce come:
Quando vengono utilizzati — per scrivere API generiche, manipolazioni su unioni, ad esempio per filtrare o abbinare modelli.
Caratteristiche:
[T], la distribuzione non avverrà. Questo è un modo per "disattivare" la distribuzione.Domanda: Il tipo T[] extends number[] ? true : false sarà distribuito?
Risposta corretta: No, la distribuzione si verifica solo se a sinistra la variabile di tipo è senza un involucro in un array o tupla. Ad esempio, il tipo condizionale T extends number ? ... distribuirà, ma T[] extends number[] ? ... — no.
Storia
Progetto: Libreria di convalida delle props per componenti React. Volevano implementare un tipo che trasformasse le props di unione in un'interfaccia rigorosa, ma a causa della mancata conoscenza della distribuzione, il tipo è diventato inaspettatamente complesso (si sono mischiati le proprietà dei membri dell'unione). Hanno corretto aggiungendo un involucro
[T], affinché la distribuzione non avvenisse.
Storia
Progetto: Sviluppavano la gestione di tutti i tipi di eventi in una funzione gestore. Nel tipo condizionale si aspettava che la funzione accettasse ogni tipo di evento tramite distribuzione, ma senza un uso esplicito della distribuzione hanno implementato la gestione in modo errato, portando a tipi di argomenti errati (unione anziché chiamate separate per ciascun tipo).
Storia
Progetto: Durante la creazione di tipi utilità personalizzati (come Exclude, Extract) hanno dimenticato che la distribuzione non avverrà per tuple e array. Di conseguenza, il tipo Exclude non funzionava per gli array (ad esempio, il tipo
Exclude<["a"|"b"], "b">non rimuoveva "b").