Pompei Tech
Guide · typescript

Introduzione a TypeScript

Introduzione a TypeScript

Immagina di dover assemblare un mobile Ikea senza le istruzioni. Nella scatola trovi solo i pezzi: viti, pannelli, cerniere, e un sacchetto di bulloni tutti uguali. Puoi comunque provare ad assemblarlo a occhio, magari ci riesci pure, ma quante probabilità hai di usare la vite sbagliata nel punto sbagliato, o di scoprire solo alla fine che hai montato un pannello al contrario? Ora immagina lo stesso mobile, ma con un libretto di istruzioni che ti dice esattamente quale pezzo va dove, con quale vite, in quale ordine. Stesso mobile, stesso risultato finale, ma un percorso completamente diverso per arrivarci.

Scrivere JavaScript è un po' come assemblare il mobile senza istruzioni. TypeScript è il libretto di istruzioni.

In questa serie di capitoli costruiremo insieme un modello mentale solido di TypeScript: non ci limiteremo a imparare la sintassi, ma capiremo come il compilatore ragiona sul nostro codice, in modo che tu possa progettare, discutere e comprendere i tipi con sicurezza, non solo copiarli da uno snippet trovato online.

Cos'è TypeScript

TypeScript è un linguaggio open source, un superset sintattico tipizzato di JavaScript. In pratica:

  • Si compila (o meglio, "transpila") in JavaScript pulito e leggibile.
  • È composto da tre parti: il linguaggio vero e proprio, il Language Server (quello che alimenta l'autocompletamento nel tuo editor) e il compilatore.
  • Puoi pensarlo, con una semplificazione, come un linter molto sofisticato che ti aiuta esclusivamente in fase di build, prima che il codice venga eseguito.

Ogni file JavaScript valido è anche un file TypeScript valido: non stai imparando un linguaggio nuovo da zero, stai aggiungendo un livello di sicurezza sopra a qualcosa che probabilmente già conosci.

Perché i tipi sono importanti

I tipi permettono a chi scrive codice di lasciare più intenzione "sulla pagina", specialmente quando si tratta di esprimere dei vincoli. Questo tipo di intenzione spesso manca completamente nel codice JavaScript. Prendi questa funzione:

js
function add(a, b) {
  return a + b;
}

Questa funzione è pensata per accettare numeri? Stringhe? Entrambi? Cosa succede se, tempo dopo, un collega interpreta a e b come numeri e aggiunge questa modifica "retrocompatibile"?

js
function add(a, b, c = 0) {
  return a + b + c;
}

Siamo nei guai se qualcuno continua a passare stringhe per a e b: il comportamento della funzione cambia silenziosamente, senza che nessuno se ne accorga fino a quando qualcosa va storto in produzione.

I tipi rendono esplicita l'intenzione di chi scrive il codice:

ts
function function add(a: number, b: number): numberadd(a: numbera: number, b: numberb: number): number {
  return a: numbera + b: numberb;
}

function add(a: number, b: number): numberadd(3, "4");
Argument of type 'string' is not assignable to parameter of type 'number'.

Questo codice è più leggibile ed è auto-documentante: è chiaro come l'autore della funzione intende che venga usata. TypeScript sposta alcune categorie di errori comuni dal runtime al momento della compilazione1. Qualche esempio:

  • Valori potenzialmente assenti (null o undefined).
  • Refactoring incompleti (hai rinominato una proprietà in un punto del codice, ma non in un altro).
  • Rotture nei "contratti" interni al codice (per esempio, un argomento che diventa obbligatorio).

TypeScript è anche la base per un'esperienza di scrittura del codice decisamente migliore: autocompletamento nell'editor, suggerimenti sui parametri delle funzioni, refactoring sicuri. Se hai mai usato Visual Studio Code su un progetto JavaScript e ti sei chiesto perché ti suggerisce i metodi disponibili su un oggetto, la risposta è: dietro le quinte, sta usando TypeScript.

Perché TypeScript per gli algoritmi e le strutture dati

Se leggi questi capitoli come preparazione al mio libro Algoritmi e Strutture Dati in TypeScript, questa domanda ha una risposta ancora più concreta. Immagina di leggere una ricetta scritta a mano da qualcuno che conosci appena. Capisci quasi tutto, ma alcune parole sono illeggibili e devi indovinare dal contesto. Ora immagina la stessa ricetta stampata, con ingredienti, quantità e passaggi indicati esplicitamente. Il contenuto è lo stesso, ma la seconda versione è molto più facile da seguire — e molto più difficile da fraintendere.

In JavaScript puoi scrivere una funzione che accetta un array, lo ordina e restituisce il risultato. Ma nulla ti impedisce di passarle una stringa, un numero o addirittura null. Il codice viene comunque eseguito, fino a quando non incontri un errore a runtime che non ti dice esattamente dove hai sbagliato. In TypeScript, quella stessa funzione dichiara esplicitamente che accetta un array di numeri e restituisce un array di numeri: se provi a passare qualcos'altro, il compilatore te lo segnala immediatamente, prima ancora che tu esegua una singola riga.

Il tuo primo assaggio di errore rilevato dal compilatore

Un altro vantaggio enorme di TypeScript è quello che vedi mentre scrivi, non solo quando compili. Se nel tuo editor scrivi:

ts
var window: Window & typeof globalThis
The **`window`** property of a Window object points to the window object itself. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/window)
window
.se
  • self
  • sessionStorage
  • setImmediate
  • setInterval
  • setTimeout

e ti fermi lì, TypeScript ti mostrerà in tempo reale l'elenco di tutte le proprietà e i metodi disponibili su window che iniziano con se (come sessionStorage, self, setTimeout...). Questo tipo di autocompletamento contestuale, alimentato dal sistema di tipi, è uno dei motivi per cui TypeScript è diventato così popolare negli ultimi anni: non ti aiuta solo a evitare errori, ti aiuta anche a scoprire le API che stai usando.

Cosa imparerai in questi capitoli

Nei prossimi capitoli vedremo, con esempi pratici prima di ogni spiegazione tecnica:

  • Come compilare ed eseguire un programma TypeScript, e cosa succede davvero "sotto il cofano".
  • Come dichiarare variabili, funzioni, oggetti, array e tuple con i tipi.
  • La differenza (fondamentale, e spesso fraintesa) tra tipizzazione strutturale e nominale.
  • Union e intersection types, per modellare valori che possono assumere forme diverse.
  • Interfacce e type alias, e quando scegliere l'uno o l'altro.
  • Le "type query" (keyof, typeof, accessi indicizzati) per derivare tipi da altri tipi.
  • Funzioni callable, overload e il tipo speciale di this.
  • Le classi TypeScript, con tutte le loro funzionalità aggiuntive rispetto a JavaScript.
  • I type guard, per restringere un tipo generico a qualcosa di più specifico.
  • I generics, per scrivere codice riutilizzabile senza perdere sicurezza sui tipi.

Non serve alcuna installazione complicata per seguire questi capitoli: ti basta un editor con supporto TypeScript (Visual Studio Code è perfetto, ed è gratuito) e, se vuoi sperimentare senza installare nulla, il TypeScript Playground ufficiale, dove puoi scrivere codice ed eseguirlo direttamente nel browser. Nel prossimo capitolo vedremo comunque come impostare un piccolo progetto TypeScript da riga di comando, così potrai anche lavorare in locale con il tuo editor preferito.

Footnotes

  1. TypeScript da solo non riduce automaticamente il numero di bug nei tuoi progetti. Ti fornisce però una serie di strumenti che migliorano enormemente la visibilità su alcune categorie di difetti, permettendoti di correggerli molto prima che diventino un problema in produzione. ↩