Padroneggia i Tipi Condizionali in TypeScript

Ah, i tipi condizionali in TypeScript... Un po' come camaleonti, cambiano forma e si adattano alle esigenze del tuo codice! Forse conosci già i tipi di base, ma con i tipi condizionali, passiamo a un livello superiore. Immagina dei tipi intelligenti che si adattano alla situazione, come supereroi della tipizzazione. Dai, mettiti comodo e preparati ad aggiungere un po' di magia al tuo codice TypeScript! 🧙‍♂️

Perché usare i tipi condizionali? 🧐

In TypeScript, amiamo quando tutto è ben organizzato, tutto ben tipizzato. Ma a volte, il nostro codice ha bisogno di un tipo che si adatti in base a certe condizioni. Immagina di avere una funzione che può restituire o una string o un number, in base ai parametri di input. 😱 Senza tipi condizionali, dovremmo gestire ogni caso manualmente, e diventa rapidamente faticoso! Fortunatamente, i tipi condizionali sono qui per portare flessibilità e reattività, un po' come un ninja della tipizzazione. 🥷

Le basi: sintassi dei tipi condizionali 🧩

I tipi condizionali sono un po' come un operatore ternario, ma per i tipi. Ecco un esempio per stuzzicare l'appetito:

typescript
1type IsString<T> = T extends string ? 'È una stringa' : 'Non è una stringa';

In questo esempio, IsString è un tipo condizionale che verifica se T è una string. Se sì, restituisce "È una stringa", altrimenti "Non è una stringa". È semplice, ma aspetta di vedere cosa possiamo fare in casi più avanzati!

Caso pratico: adattare un tipo in base alla configurazione 🛠️

Immaginiamo una funzione che prende un parametro di configurazione e deve restituire un tipo diverso in base a questa configurazione. I tipi condizionali sono perfetti per questo tipo di magia ✨!

Esempio di codice

typescript
1type Config = {
2 mode: 'semplice' | 'dettagliato';
3};
4
5type Response<T extends Config> = T['mode'] extends 'semplice'
6 ? { data: string }
7 : { data: string; details: string[] };
8
9function fetchData<T extends Config>(config: T): Response<T> {
10 if (config.mode === 'semplice') {
11 return { data: 'Dati semplificati' } as Response<T>;
12 } else {
13 return {
14 data: 'Dati completi',
15 details: ['dettaglio1', 'dettaglio2'],
16 } as Response<T>;
17 }
18}
19
20const simpleConfig = { mode: 'semplice' };
21const detailedConfig = { mode: 'dettagliato' };
22
23const resultSimple = fetchData(simpleConfig); // { data: "Dati semplificati" }
24const resultDetailed = fetchData(detailedConfig); // { data: "Dati completi", details: [...] }

In questo esempio, Response<T> adatta il tipo a seconda che mode sia "semplice" o "dettagliato". La magia funziona: fetchData(simpleConfig) restituisce un oggetto con solo data, mentre fetchData(detailedConfig) include anche details. Pratico, vero?

Tipi condizionali annidati: tipizzazione su misura 🧇

Perché fermarsi qui? Puoi anche annidare i tipi condizionali per gestire casi ancora più precisi! Immagina di voler adattare il tipo non solo in base al mode, ma anche in base all'autenticazione dell'utente. Pronto per vedere dell'alta acrobazia tipografica? 🎢

typescript
1type UserResponse<
2 T extends Config,
3 Authenticated extends boolean,
4> = Authenticated extends true
5 ? T['mode'] extends 'semplice'
6 ? { data: string }
7 : { data: string; details: string[] }
8 : { error: 'Non autenticato' };
9
10function fetchUserData<T extends Config, Authenticated extends boolean>(
11 config: T,
12 isAuthenticated: Authenticated,
13): UserResponse<T, Authenticated> {
14 if (!isAuthenticated) {
15 return { error: 'Non autenticato' } as UserResponse<T, Authenticated>;
16 }
17 if (config.mode === 'semplice') {
18 return { data: 'Dati semplificati' } as UserResponse<T, Authenticated>;
19 } else {
20 return {
21 data: 'Dati completi',
22 details: ['dettaglio1', 'dettaglio2'],
23 } as UserResponse<T, Authenticated>;
24 }
25}
26
27const resultAuthSimple = fetchUserData(simpleConfig, true); // { data: "Dati semplificati" }
28const resultAuthDetailed = fetchUserData(detailedConfig, true); // { data: "Dati completi", details: [...] }
29const resultNotAuth = fetchUserData(detailedConfig, false); // { error: "Non autenticato" }

Qui, UserResponse adatta il tipo in base a due criteri: mode e isAuthenticated. Risultato? Una tipizzazione ultra-precisa che copre tutti i casi possibili!

Tipi condizionali avanzati con infer: deduzione del tipo 🕵️‍♂️

Pronto per un piccolo trucco di magia? TypeScript offre una parola chiave speciale nei tipi condizionali: infer. Grazie a questa, puoi dedurre un tipo direttamente nel tuo tipo condizionale. Utile per estrarre informazioni da tipi complessi!

Esempio con infer

typescript
1type ReturnTypeOfFunction<T> = T extends (...args: any[]) => infer R
2 ? R
3 : never;
4
5function getHello(): string {
6 return 'Hello, world!';
7}
8
9type HelloReturnType = ReturnTypeOfFunction<typeof getHello>; // Risultato: string

Qui, ReturnTypeOfFunction usa infer R per dedurre il tipo di ritorno di una funzione. In questo esempio, HelloReturnType sarà di tipo string, poiché getHello restituisce una stringa.

Conclusione 🎉

I tipi condizionali in TypeScript sono come un superpotere per il tuo codice. Ti permettono di creare tipi dinamici e mantenere una tipizzazione rigorosa, alleggerendo allo stesso tempo il codice. Allora, pronto a stupire i tuoi colleghi? Sperimenta con questi tipi condizionali e scopri nuovi modi di strutturare il tuo codice TypeScript! 🚀

Non ci sono più scuse per i tipi approssimativi: con i tipi condizionali, il tuo codice TypeScript diventa semplicemente infallibile! 👌

Condividi questo articolo


Sébastien Timoner

Sébastien TIMONER

Lead Developer
Esperto in Sviluppo su Misura
Aix-en-Provence, France

Esperto nello sviluppo web e nella gestione di team tecnici, mi specializzo nella creazione e ottimizzazione di soluzioni digitali performanti. Grazie a una profonda padronanza di tecnologie moderne come React.js, Node.js, TypeScript e Symfony, garantisco il successo di progetti SaaS complessi, dalla progettazione alla messa in produzione, per aziende di diversi settori, all'interno di offroadLabs.

In offroadLabs, offro servizi di sviluppo su misura, combinando competenza tecnica e approccio collaborativo. Che si tratti di creare una soluzione SaaS innovativa, modernizzare un'applicazione esistente o accompagnare la crescita professionale di un team, mi impegno a fornire soluzioni robuste e performanti, adattate alle esigenze specifiche di ogni progetto.

Sono disponibile per incarichi intorno ad Aix-en-Provence o in full remote.