CONTATTACI

Guide per aspiranti programmatori

sviluppatore web che lavora alla scrivania con un fumetto con 3 puntini di sospensione
Lezione 17 / 30

Tipi enumerativi in Typescript

A volte ci troviamo in presenza di tipi di dato il cui unico scopo è quello di discriminare tra un elenco finito di opzioni. 

Prendiamo ad esempio la seguente funzione, che presenta uno switch statement:

 

function log(level: string, message: string): void { 
 switch (level) { 
 case "log": 
 console.log(message); 
 return; 
 case "info": 
 console.info(message); 
 return; 
 case "warning": 
 console.warn(message); 
 return; 
 case "error": 
 console.error(message); 
 return;
 } 
} 

Lo scopo della funzione log è di unificare la chiamata ai diversi metodi di console, passando un parametro level il cui scopo è quello di discriminare quale livello di severità applicare. Il problema è che, definendo level: string, ammettiamo anche valori che non hanno senso rispetto ai casi definiti. 

Un modo per evitare questo problema a runtime è aggiungere un caso default nel nostro blocco switch, e scatenare un’eccezione:

 

function log(level: string, message: string): void { 
 switch (level) { 
 case "log": 
 console.log(message); 
 return; 
 case "info": 
 console.info(message); 
 return; 
 case "warning": 
 console.warn(message); 
 return; 
 case "error": 
 console.error(message); 
 return; 
 default: 
 throw new Error("Invalid log level value"); 
 } 
} 

Sicuramente considerare tutte le casistiche è un’ottima pratica, ma TypeScript può aiutarci con una dichiarazione di tipo molto speciale, introdotta dalla parola chiave enum

 

enum LogLevel { 
 Log, 
 Info, 
 Warning, 
 Error 
} 
function log(level: LogLevel, message: string): void { 
 switch (level) { 
 case LogLevel.Log: 
 console.log(message); 
 return; 
 case LogLevel.Info: 
 console.info(message); 
 return; 
 case LogLevel.Warning: 
 console.warn(message);
 return; 
 case LogLevel.Error: 
 console.error(message); 
 return; 
 } 
} 

Quando dichiariamo un tipo enum, non facciamo altro che elencare i possibili valori che questo tipo può assumere, senza preoccuparci di individuare un valore corrispondente per le diverse opzioni. Proprio per questo motivo, la dichiarazione di tipi enum è così particolare: è uno dei rari casi in cui il compilatore scrive attivamente codice JavaScript al posto nostro, invece che limitarsi a verificare e rimuovere le dichiarazioni e le annotazioni di tipo. 

Non è un caso che per l’esempio sia stato usato un costrutto switch: i tipi enum si prestano particolarmente per questo genere di casistiche, permettendo al type checker di limitare i valori alle sole opzioni definite dal tipo, e all’IDE di suggerirci l’autocompletamento di tutti i case

Visto che i tipi enum comportano un’implementazione JavaScript, vediamo un attimo il codice generato dal compilatore per LogLevel:

 

var LogLevel; 
(function (LogLevel) { 
 LogLevel[LogLevel["Log"] = 0] = "Log"; 
 LogLevel[LogLevel["Info"] = 1] = "Info"; 
 LogLevel[LogLevel["Warning"] = 2] = "Warning"; 
 LogLevel[LogLevel["Error"] = 3] = "Error"; 
})(LogLevel || (LogLevel = {}));

Il risultato di questo stranissimo codice è, in effetti, molto più semplice di quello che sembra; questo è il valore di LogLevel dopo l’esecuzione di questa strana funzione:

 

{ 
 '0': 'Log', 
 '1': 'Info', 
 '2': 'Warning', 
 '3': 'Error', 
 Log: 0, 
 Info: 1, 
 Warning: 2, 
 Error: 3 
}

In pratica, TypeScript ha creato un oggetto che mappa dei valori numerici ai nomi delle opzioni dell’enum, e poi mappa le opzioni dell’enum agli stessi valori numerici. Come mai questa strana simmetria? 

Il punto è che, affinché JavaScript possa attribuire un significato alle opzioni enumerate, queste corrispondono in realtà a dei numeri che iniziano da 0, a salire. È anche possibile iniziare da numeri diversi da 0, oppure attribuire valori arbitrari ad ogni singola opzione: 

 

enum OneToFour { 
 One = 1, 
 Two = 2, 
 Three = 3 
 Four = 4 
} 
enum PrimeNumbers { 
 Two = 2, 
 Three = 3, 
 Five = 5 
}

Grazie a questa implementazione così sofisticata, potremo accedere ai diversi valori dell’enum sia attraverso il loro indice numerico, sia attraverso il nome delle opzioni:

 

enum LogLevel { 
 Log, 
 Info, 
 Warning, 
 Error 
} 
const log = LogLevel["Log"]; 
console.log(log); // 0 
const info = LogLevel[1]; 
console.log(info); // Info

TypeScript ci offre anche la possibilità di dare valori stringa alle opzioni dell’enum, il che semplifica il codice risultante:

 

enum LogLevel { 
 Log = "Log", 
 Info = "Info", 
 Warning = "Warning", 
 Error = "Error" 
} 
const log = LogLevel.Log; 
console.log(log); // Log

Questo codice risulta nel seguente JavaScript:

 

var LogLevel; 
(function (LogLevel) { 
 LogLevel["Log"] = "Log"; 
 LogLevel["Info"] = "Info"; 
 LogLevel["Warning"] = "Warning"; 
 LogLevel["Error"] = "Error"; 
})(LogLevel || (LogLevel = {})); 
var log = LogLevel.Log; 
console.log(log); // Log

In effetti, l’implementazione risulta più semplice perché, a questo punto, non è più necessario mappare gli indici numerici. 

Gli enum sono molto pratici quando dobbiamo discriminare tra un numero finito di possibilità, e sono ampiamente utilizzati in linguaggi di programmazione tendenzialmente orientati agli oggetti come il linguaggio C# e il linguaggio Java. Ad ogni modo, poiché gli enum nascondono un’implementazione e, in fin dei conti, rappresentano dei normalissimi valori numerici o testuali dietro a un tipo, sono ritenuti abbastanza eccezionali in TypeScript e hanno un utilizzo circoscritto a determinate casistiche come quella mostrata nell’esempio o a stili di programmazione fortemente orientati agli oggetti. 

Più avanti vedremo come combinare i tipi algebrici e quelli letterali per ottenere qualcosa di simile a dei tipi enum, ma senza la complessità introdotta dalla loro implementazione.

Contattaci senza impegno per informazioni sul corso

Pagamento rateale

Valore della rata: A PARTIRE DA 115 €/mese.

Esempio di finanziamento 

Importo finanziato: € 2440 in 24 rate da € 115 – TAN fisso 9,55% TAEG 12,57% – importo totale del credito € 2841.

Il costo totale del credito comprende: interessi calcolati al TAN indicato, oneri fiscali (imposta di bollo sul contratto 16,00 euro*) addebitati sulla prima rata, costo mensile di gestione pratica € 3,90, spesa di istruttoria € 0,00, spesa per invio rendicontazione periodica cartacea € 0,98 (o spesa per invio rendicontazione periodica cartacea € 0,00), imposta di bollo su rendicontazione periodica € 0,00. Modalità di rimborso obbligatoria: addebito diretto su c/c. La scadenza delle rate è determinata dal giorno della liquidazione del contratto; la data di scadenza delle rate è prevista il giorno 15 del mese. L’importo di ciascuna rata comprende una quota di capitale crescente e interessi decrescente secondo un piano di ammortamento “alla francese”. Offerta valida dal 01/01/2024 al 31/12/2024.

Messaggio pubblicitario con finalità promozionale. Per le informazioni precontrattuali richiedere sul punto vendita il documento “Informazioni europee di base sul credito ai consumatori” (SECCI) e copia del testo contrattuale. Salvo approvazione di Sella Personal Credit S.p.A. Aulab S.r.l. opera quale intermediario del credito NON in esclusiva.

*In fase di richiesta del finanziamento verrà proposta la facoltà di selezionare, in alternativa all’imposta di bollo sul contratto di 16,00 euro, l’imposta sostitutiva, pari allo 0,25% dell’importo finanziato.

Pagamento rateale

Valore della rata: A PARTIRE DA 187 €/mese.

Esempio di finanziamento  

Importo finanziato: € 3990 in 24 rate da € 187 – TAN fisso 9,55% TAEG 12,57% – importo totale del credito € 4572.88.

Il costo totale del credito comprende: interessi calcolati al TAN indicato, oneri fiscali (imposta di bollo sul contratto 16,00 euro*) addebitati sulla prima rata, costo mensile di gestione pratica € 3,90, spesa di istruttoria € 0,00, spesa per invio rendicontazione periodica cartacea € 0,98 (o spesa per invio rendicontazione periodica cartacea € 0,00), imposta di bollo su rendicontazione periodica € 0,00. Modalità di rimborso obbligatoria: addebito diretto su c/c. La scadenza delle rate è determinata dal giorno della liquidazione del contratto; la data di scadenza delle rate è prevista il giorno 15 del mese. L’importo di ciascuna rata comprende una quota di capitale crescente e interessi decrescente secondo un piano di ammortamento “alla francese”. Offerta valida dal 01/01/2024 al 31/12/2024.

Messaggio pubblicitario con finalità promozionale. Per le informazioni precontrattuali richiedere sul punto vendita il documento “Informazioni europee di base sul credito ai consumatori” (SECCI) e copia del testo contrattuale. Salvo approvazione di Sella Personal Credit S.p.A. Aulab S.r.l. opera quale intermediario del credito NON in esclusiva.

* In fase di richiesta del finanziamento verrà proposta la facoltà di selezionare, in alternativa all’imposta di bollo sul contratto di 16,00 euro, l’imposta sostitutiva, pari allo 0,25% dell’importo finanziato.

Contattaci senza impegno per informazioni sul corso

Scopriamo insieme se i nostri corsi fanno per te. Compila il form e aspetta la chiamata di uno dei nostri consulenti.