Perché nasce TypeScript

JavaScript è uno dei linguaggi più utilizzati per lo sviluppo web e può essere eseguito sia nei browser sia in ambienti server come Node.js. La sua flessibilità, però, può portare a errori difficili da individuare, soprattutto nei progetti più grandi.

TypeScript nasce proprio per aggiungere a JavaScript un sistema di tipi statico e rendere il codice più prevedibile e facile da mantenere.

In questa lezione vedremo quali sono i principali limiti di JavaScript che hanno portato alla nascita di TypeScript, come funziona il controllo statico dei tipi e come il codice TypeScript viene trasformato in JavaScript.

I limiti di JavaScript

JavaScript è un linguaggio a tipizzazione dinamica. Questo significa che non è necessario dichiarare esplicitamente il tipo di una variabile e che il tipo di un valore può cambiare durante l'esecuzione del programma.

Ad esempio:

let valore = 10;

valore = "ciao";

Lo stesso nome valore viene prima associato a un numero e successivamente a una stringa. JavaScript permette questo comportamento senza generare necessariamente un errore.

Questa flessibilità può essere utile in alcune situazioni, ma può anche causare comportamenti inattesi.

Errori con tipi diversi

Consideriamo una funzione che dovrebbe sommare due numeri:

function somma(a, b) {
    return a + b;
}

Possiamo utilizzarla correttamente in questo modo:

somma(10, 5); // 15

Ma JavaScript permette anche:

somma(10, "5"); // "105"

In questo caso il risultato sarà la stringa 105.

Il motivo è che l'operatore +, quando viene utilizzato con una stringa, può effettuare una concatenazione invece di una somma numerica.

Il problema non è necessariamente JavaScript in sé: il linguaggio sta applicando le proprie regole. Tuttavia, se la funzione era stata progettata per lavorare esclusivamente con numeri, questo comportamento potrebbe rappresentare un errore nel nostro programma.

Errori individuati durante l'esecuzione

Un altro aspetto importante è capire il momento in cui vengono individuati gli errori.

JavaScript viene normalmente eseguito direttamente dal browser o da Node.js. Alcuni problemi vengono quindi scoperti soltanto quando il codice raggiunge quella determinata istruzione.

Prendiamo questo codice come esempio:

const utente = {
    nome: "Marco"
};

console.log(utente.nome.toUpperCase());

Questo codice funziona perché nome contiene una stringa. Se però il valore fosse un numero, la chiamata provocherebbe un errore durante l'esecuzione, perché un numero non dispone del metodo toUpperCase():

const utente = {
    nome: 10
};

utente.nome.toUpperCase(); // Errore

In un progetto di grandi dimensioni, individuare questo tipo di problema soltanto durante l'esecuzione può diventare complicato.

Il Type Checking statico

TypeScript introduce un sistema di controllo statico dei tipi, chiamato static type checking.

Il termine "statico" indica che i tipi possono essere controllati prima dell'esecuzione del programma.

Per esempio, possiamo dichiarare che una funzione deve ricevere due numeri:

function somma(a: number, b: number) {
    return a + b;
}

Se proviamo a passarle una stringa, TypeScript segnala un errore già durante il controllo del codice:

somma(10, "5");

In questo modo possiamo individuare determinati problemi prima che il programma venga eseguito.

TypeScript è un superset di JavaScript

TypeScript viene definito un superset di JavaScript: significa che il codice JavaScript valido è, in linea generale, anche codice TypeScript valido.

Per esempio, questo codice può essere utilizzato anche in un file TypeScript:

const nome = "Marco";

console.log(nome);

TypeScript aggiunge però funzionalità che JavaScript non possiede, tra cui soprattutto il sistema di tipi statico.

Possiamo quindi partire da JavaScript:

function saluta(nome) {
    return "Ciao " + nome;
}

Dall'esempio, possiamo poi aggiungere informazioni sui tipi:

function saluta(nome: string): string {
    return "Ciao " + nome;
}

La sintassi aggiuntiva permette a TypeScript di conoscere il tipo del parametro nome e quello del valore restituito dalla funzione.