CONTATTACI

Guide per aspiranti programmatori

data analyst alla scrivania che analizza dati con istogrammi e grafici a torta
Lezione 12 / 30

Conversioni, asserzioni e restringimento in Typescript

Conversione di tipo in Typescript

In diversi linguaggi di programmazione, il concetto di tipo si accompagna al concetto di type casting, cioè di conversione di tipo. Senza scomodare altri linguaggi, vediamo il seguente codice JavaScript:

 

const one = Number("1");

Abbiamo il valore letterale “1” che rappresenta una stringa, convertito in numero dalla funzione Number e conservato nella costante one. In altre parole, abbiamo effettuato una conversione di tipo. Se tale conversione non fosse stata possibile, Number avrebbe restituito NaN (not a number, che ironicamente è un valore di tipo number). Lo stesso tipo di conversione in JavaScript può essere effettuato analogamente con Boolean e String

In questo modo possiamo effettuare la conversione tra tipi semplici in JavaScript, e TypeScript sarà sempre allineato sui tipi in uso. 

Immaginiamo ora di avere un’informazione di tipo che TypeScript non può in alcun modo inferire: 

 

const data = JSON.parse('{ "name": "John" }'); // const data: any 
console.log(data.name);

In questo caso, l’argomento di JSON.parse è semplicemente una stringa, e potenzialmente questa stringa potrebbe venire da un punto esterno al nostro codice, come un file, un database o una risposta HTTP; quindi, TypeScript non può dedurre che data ha una proprietà name di tipo string! 

Come vedremo più avanti, any è un tipo speciale che rappresenta qualunque tipo, ed è usato appositamente per sopprimere gli avvertimenti del type checker sull’uso di una certa variabile, motivo per cui qui TypeScript non batte ciglio alla vista di data.name. Vedremo anche come è possibile rendere TypeScript meno “ingenuo” di fronte ai valori di tipo sconosciuto

Quindi, come facciamo a tipizzare data?  Vediamolo.

 

Asserzione di tipo in Typescript

Ricollegandoci all’esempio precedente, per tipizzare data ci viene incontro la keyword as, che introduce un’asserzione di tipo (in inglese: type assertion). Usando as stiamo dicendo al type checker: “quest’informazione te la do io, e ti puoi fidare”. 

Vediamolo in pratica: 

 

const data = JSON.parse('{ "name": "John" }') as { name: string };

Ora che abbiamo istruito TypeScript su come qualificare data, se digitiamo data. nell’IDE, ci verrà automaticamente suggerito di navigare verso la proprietà name

Vediamo ora il seguente esempio: 

 

const a = 1; // const a: number 
const b = a as string; // Conversion of type 'number' to type 'string' may be a mistake ...

In questo caso, TypeScript ci sta segnalando che la nostra type assertion è priva di senso e probabilmente errata, perché in base alle informazioni disponibili sul tipo di a, non è possibile asserire che b sia una stringa. Dunque TypeScript ammette asserzioni solo laddove si vada ad allargare oppure a restringere la specificità di un tipo. 

In pratica, qui il problema è che il tipo string non è un sottoinsieme del tipo number né viceversa, quindi non ha senso interpretare un numero come una stringa; avrebbe invece senso convertire un numero in una stringa: 

 

const a = 1; // const a: number 
const b = String(a); // const b: string

Prendiamo, invece, la seguente funzione: 

function concat(a: string | number, b: string | number): string { 
 return a + b; // Operator '+' cannot be applied to types 'string | number' and 'string | number'. 
}

Qui TypeScript, giustamente, protesta perché l’operatore + ha due comportamenti diversi se applicato a numeri o a stringhe. In questo caso, noi potremmo asserire che a e b siano stringhe, ma finiremmo con l’introdurre un bug, perché se questi fossero numeri, il risultato della funzione non sarebbe la loro concatenazione, ma la loro somma algebrica. 

Dunque, la cosa migliore sarebbe operare una conversione a stringa, e ci basterà farlo su a perché è sufficiente che uno dei due operandi sia stringa per determinare il comportamento dell’operatore +

 

function concat(a: string | number, b: string | number): string { 
 return String(a) + b; 
}

A questo punto, per TypeScript è tutto a posto: un numero può sempre essere convertito in una stringa, e l’operatore + applicato dopo una stringa eseguirà in automatico un’eventuale conversione a stringa anche per b, restituendo la concatenazione anziché la somma algebrica. 

Ma immaginiamo di voler effettuare la conversione solo se necessario; significa che, nel caso in cui a fosse già una stringa, potremmo procedere direttamente alla “somma” tra stringhe: 

 

function concat(a: string | number, b: string | number): string { 
 if (typeof a === "string") return a + b; // a: string 
 return String(a) + b; 
}

In questo caso TypeScript non protesterà, perché il type checker è in grado di intuire che a è una stringa nel primo caso, e un numero nel secondo. 

La capacità di TypeScript di restringere il tipo di una variabile tra più tipi possibili in base alle condizioni verificate dal codice è detta restringimento di tipo, in inglese type narrowing

 

Restringimento di tipo in Typescript

Esistono molti modi in cui TypeScript può restringere il tipo di una variabile, vediamone alcuni: 

 

function f(a: number | string | number[] | null) { 
 // valorizzazione/non-nullità 
 if (a) ... // a: number | string | number[] 
 // typeof 
 if (typeof a === "number") ... // a: number 
 if (typeof a === "object") ... // a: number[] | null 
 // instanceof 
 if (a instanceof Array) ... // a: number[] 
 // uguaglianza 
 if (a === null) ... // a: null 
}

In pratica, invece di prenderci noi la responsabilità di fare un’asserzione, faremo delle verifiche di tipo a runtime, come se stessimo lavorando in JavaScript puro: TypeScript a quel punto saprà con assoluta certezza che i tipi possibili di quella variabile saranno ristretti in base alla condizione verificata. 

Abbiamo dunque visto come muoverci tra diversi tipi, ma abbiamo appena grattato la superficie; prima di addentrarci nel dettaglio del type system, vediamo come TypeScript ci aiuta non solo a validare il codice, ma anche e soprattutto a scriverlo

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.