TypeScript è un linguaggio di programmazione che estende JavaScript aggiungendo una sintassi per descrivere i tipi e un sistema di controllo statico capace di individuare molti errori prima che il codice venga eseguito. Non sostituisce JavaScript come runtime: nella toolchain classica il codice TypeScript viene controllato e trasformato in JavaScript, che sarà poi eseguito dal browser, da Node.js o da un altro ambiente compatibile.
Questa distinzione è il punto da cui conviene partire. TypeScript non rende automaticamente corretto un programma e non valida da solo i dati che arrivano da una rete, da un form o da un file JSON. Aggiunge però un livello di informazioni che permette al compilatore e all’editor di capire molto meglio quali valori dovrebbero passare da una funzione all’altra, quali proprietà deve avere un oggetto e dove il codice sta facendo assunzioni incoerenti.
Se conosci già le basi di JavaScript, puoi pensare a TypeScript come a un modo per rendere più espliciti i contratti del programma. In questa guida vediamo come funziona, quali tipi servono davvero per iniziare, cosa cambia rispetto a JavaScript, quali vantaggi offre e soprattutto dove sono i suoi limiti.
Cos’è TypeScript e che rapporto ha con JavaScript
TypeScript viene spesso definito un “superset di JavaScript”. La formula è utile, ma rischia di essere interpretata male se la riduciamo a “JavaScript con più funzioni”.
Il punto centrale è che TypeScript si costruisce sopra il modello di JavaScript. Mantiene la sintassi e il comportamento del linguaggio, aggiungendo soprattutto informazioni utilizzate dagli strumenti di sviluppo per analizzare il codice prima dell’esecuzione. La documentazione ufficiale lo descrive infatti come uno static typechecker per programmi JavaScript: un sistema che lavora prima del runtime e verifica che i tipi utilizzati siano coerenti con quelli attesi.
TypeScript è JavaScript con una sintassi per i tipi
Considera una normale funzione JavaScript:
function saluta(nome) {
return `Ciao ${nome}`;
}
In TypeScript puoi specificare il tipo del parametro e del valore restituito:
function saluta(nome: string): string {
return `Ciao ${nome}`;
}
L’annotazione : string dice al type checker che nome deve essere una stringa. Se provi a chiamare la funzione in questo modo:
saluta(42);
TypeScript può segnalare l’incompatibilità durante lo sviluppo, prima che quel percorso venga eseguito dall’applicazione.
Questo non significa che ogni variabile debba essere annotata manualmente. Il sistema utilizza ampiamente l’inferenza dei tipi: quando scrivi const nome = "Anna", TypeScript può già dedurre che quel valore è una stringa.
Cosa significa davvero “superset di JavaScript”
L’idea di superset riguarda soprattutto la relazione sintattica e l’adozione progressiva. TypeScript nasce per lavorare con l’ecosistema JavaScript e consente di aggiungere gradualmente informazioni di tipo a un progetto.
Il contrario, però, non è vero: una sintassi TypeScript come questa non è normale JavaScript:
const prezzo: number = 19.9;
Un ambiente JavaScript tradizionale non usa quell’annotazione per decidere come eseguire il programma. Nella toolchain TypeScript classica, le informazioni di tipo vengono controllate e poi eliminate dal codice emesso.
È quindi più preciso pensare alla relazione così:
JavaScript + informazioni di tipo + type checker + tooling = esperienza TypeScript
Linguaggio, type checker, compilatore e runtime non sono la stessa cosa
Quattro concetti vengono spesso mescolati:
- linguaggio: la sintassi e le regole che utilizzi quando scrivi TypeScript;
- type checker: analizza le relazioni tra i tipi e segnala incoerenze;
- compiler/toolchain: gestisce il progetto e può produrre JavaScript a partire dai file TypeScript;
- runtime: è l’ambiente che esegue il programma, come un browser o Node.js.
La distinzione evita un errore concettuale frequente: TypeScript può dichiarare che un valore dovrebbe essere un number, ma questa informazione non crea un nuovo tipo numerico a runtime. Quando il programma viene eseguito come JavaScript, valgono le regole del runtime JavaScript.
Come funziona TypeScript
Il modello più semplice da ricordare è:
codice TypeScript → analisi dei tipi → eventuale JavaScript emesso → runtime
In molti progetti moderni build tool e framework inseriscono altri passaggi, ma il principio rimane: il controllo statico avviene prima dell’esecuzione e non deve essere confuso con ciò che il programma farà quando riceverà dati reali.
Il type checking avviene prima dell’esecuzione
Supponiamo di avere questa funzione:
function formattaPrezzo(prezzo: number): string {
return prezzo.toFixed(2);
}
Questa chiamata è coerente:
formattaPrezzo(19.9);
Questa invece non lo è:
formattaPrezzo("19.90");
Una stringa non soddisfa il contratto number. In JavaScript puro l’errore potrebbe emergere solo quando quella riga viene realmente eseguita e il programma tenta di usare toFixed() sul valore sbagliato. TypeScript può anticipare il problema.
Il vantaggio non è “zero bug”. È spostare una classe di errori verso una fase in cui costa meno individuarli.
Inferenza dei tipi e annotazioni esplicite
Uno dei modi peggiori per imparare TypeScript è annotare qualsiasi cosa.
Questo codice è perfettamente comprensibile per il compilatore:
const quantita = 3; const prodotto = "Monitor"; const disponibile = true;
TypeScript può inferire rispettivamente number, string e boolean.
Le annotazioni diventano particolarmente utili quando definiscono un confine: parametri di funzione, oggetti condivisi, API interne, callback, valori restituiti pubblicamente da un modulo o dati che devono rispettare una struttura precisa.
In altre parole, non usare i tipi come decorazione. Usali dove chiariscono l’intento del codice.
Cosa succede ai tipi quando viene prodotto JavaScript
Prendiamo:
function raddoppia(valore: number): number {
return valore * 2;
}
Il JavaScript emesso, semplificando, non ha bisogno delle annotazioni:
function raddoppia(valore) {
return valore * 2;
}
Le informazioni : number hanno già svolto il loro compito durante l’analisi. La documentazione TypeScript parla di erased types: i tipi vengono rimossi dal risultato JavaScript e non modificano automaticamente il comportamento del programma durante l’esecuzione.
Questa è una delle ragioni per cui TypeScript non può sostituire la validazione runtime.

tsc, tsconfig.json ed editor: i componenti della toolchain
Il comando tsc è il compilatore TypeScript da riga di comando. In un progetto puoi installarlo come dipendenza di sviluppo e utilizzarlo per controllare o compilare i file.
tsconfig.json descrive invece il progetto TypeScript: quali file include, come risolvere i moduli, quanto deve essere rigoroso il controllo e come produrre l’output quando è previsto l’emit.
L’editor completa il quadro. Autocompletamento, go-to-definition, rename symbol e molte funzioni di refactoring diventano più affidabili perché gli strumenti possiedono una rappresentazione più ricca delle relazioni tra i valori.
La TSConfig Reference ufficiale documenta le opzioni disponibili. Per un progetto reale conviene evitare di copiare configurazioni casuali: le impostazioni corrette dipendono dal runtime e dalla toolchain che userà il codice.
Un esempio pratico: da JavaScript a TypeScript
Un piccolo esempio vale più di una definizione astratta.
Lo stesso codice scritto in JavaScript
Immagina una funzione che calcola il totale di un ordine:
function totaleOrdine(prezzo, quantita) {
return prezzo * quantita;
}
console.log(totaleOrdine(20, 3));
Fin qui tutto bene. Ma JavaScript accetta anche:
totaleOrdine("venti", 3);
Il problema non è che JavaScript sia “sbagliato”: è un linguaggio dinamico e il programma è libero di ricevere valori differenti. Il problema è che l’intento della funzione non è espresso in modo verificabile.
Aggiungere tipi a parametri e valori restituiti
In TypeScript possiamo dichiararlo:
function totaleOrdine(prezzo: number, quantita: number): number {
return prezzo * quantita;
}
Adesso il contratto è leggibile sia da una persona sia dagli strumenti.
La chiamata:
totaleOrdine("venti", 3);
viene segnalata perché il primo argomento non è compatibile con number.
Un errore che TypeScript può intercettare prima del runtime
Il valore emerge soprattutto quando una struttura viene modificata.
interface Prodotto {
id: number;
nome: string;
prezzo: number;
}
function etichetta(prodotto: Prodotto): string {
return `${prodotto.nome}: €${prodotto.prezzo.toFixed(2)}`;
}
Se in seguito qualcuno cambia prezzo in string, tutte le parti del codice che dipendono dal comportamento numerico possono essere rivalutate dal type checker.
In una codebase grande questo è molto più importante dell’autocompletamento: un cambiamento locale può rendere visibili le conseguenze in punti lontani del progetto.
I tipi TypeScript che servono per iniziare
Non devi conoscere conditional types e metaprogrammazione avanzata per usare TypeScript in modo produttivo. Per iniziare servono pochi concetti ben compresi.
string, number, boolean, array e oggetti
I tipi primitivi più comuni sono:
const nome: string = "Elena"; const eta: number = 32; const attivo: boolean = true;
Per gli array:
const prezzi: number[] = [19.9, 25, 42];
oppure:
const prezzi: Array<number> = [19.9, 25, 42];
Per un oggetto puoi descrivere direttamente la forma:
function mostraUtente(utente: { nome: string; eta: number }) {
console.log(`${utente.nome}, ${utente.eta}`);
}
Quando quella struttura viene riutilizzata, normalmente conviene darle un nome.
Union types e valori opzionali
Una union descrive un valore che può appartenere a più tipi ammessi:
type Id = string | number;
function cerca(id: Id) {
// ...
}
Un campo opzionale utilizza ?:
interface Utente {
id: number;
nome: string;
telefono?: string;
}
“Opzionale” non significa “sempre una stringa”. Significa che quella proprietà può anche non essere presente, e il codice deve tenerne conto quando necessario.
Interface e type alias
Entrambi possono descrivere strutture riutilizzabili:
interface Cliente {
id: number;
nome: string;
}
oppure:
type Cliente = {
id: number;
nome: string;
};
Esistono differenze tra interface e type, soprattutto quando entrano in gioco estensione, declaration merging e composizioni più complesse. Per chi inizia, però, è più importante capire il principio: dare un nome a una forma o a una relazione tra tipi.
Non serve trasformare questa scelta in una guerra di stile. Segui le convenzioni del progetto e usa lo strumento che esprime meglio il modello.
Narrowing: restringere un tipo in base al codice
Se un valore può essere string | number, non puoi utilizzare liberamente un metodo disponibile solo sulle stringhe.
function normalizzaId(id: string | number): string {
if (typeof id === "string") {
return id.trim();
}
return id.toString();
}
Nel ramo if, il controllo typeof id === "string" permette a TypeScript di restringere il tipo. Questo meccanismo prende il nome di narrowing ed è centrale perché collega il controllo dei tipi al normale flusso del programma.
Generics: riutilizzare codice mantenendo informazione sui tipi
Un generic permette di esprimere una relazione senza perdere il tipo specifico del valore.
function primo<T>(elementi: T[]): T | undefined {
return elementi[0];
}
const primoNumero = primo([10, 20, 30]);
const primaParola = primo(["uno", "due"]);
La funzione funziona con tipi differenti, ma TypeScript mantiene informazione sul tipo dell’array ricevuto e quindi sul possibile risultato.
Questo è molto diverso da usare any, che disattiva gran parte del controllo e rende più difficile capire cosa stia davvero passando attraverso il programma.
TypeScript vs JavaScript: quali sono le differenze
TypeScript e JavaScript non sono due ecosistemi completamente separati. TypeScript dipende dalle fondamenta di JavaScript e viene usato proprio perché permette di lavorare nello stesso ambiente aggiungendo un livello di analisi statica.
| Aspetto | JavaScript | TypeScript |
|---|---|---|
| Tipizzazione | Dinamica | Controllo statico dei tipi durante lo sviluppo |
| Annotazioni di tipo | Non fanno parte della sintassi standard | Disponibili e spesso opzionali grazie all’inferenza |
| Errori di tipo | Possono emergere a runtime o tramite tooling | Molti possono essere individuati prima dell’esecuzione |
| Output | Viene eseguito direttamente da runtime compatibili | Nella toolchain classica viene controllato e può essere emesso come JavaScript |
| Tooling | Molto evoluto anche senza TypeScript | Può sfruttare informazioni di tipo più esplicite |
| Configurazione | Può essere minima | Può richiedere tsconfig, build e scelte di integrazione |
| Curva iniziale | Più diretta | Richiede JavaScript + modello dei tipi + configurazione |
| Runtime safety | Dipende dal codice e dalle validazioni eseguite | I tipi statici non sostituiscono la validazione runtime |
Errori compile-time e runtime
È facile trasformare questa differenza in uno slogan sbagliato: “JavaScript scopre gli errori a runtime, TypeScript in compilazione”.
La realtà è più precisa. TypeScript può individuare errori che il suo sistema di tipi riesce a modellare. Un timeout di rete, una risposta API malformata, un problema di autorizzazione, un valore corrotto nel database o un bug nella logica possono continuare a manifestarsi durante l’esecuzione.
Il type checker riduce lo spazio degli errori possibili; non elimina il runtime.
Tooling, autocompletamento e refactoring
Conoscere i tipi permette all’editor di capire meglio il codice.
Se rinomini una proprietà usata in decine di moduli, cambi la firma di una funzione o modifichi la forma di un oggetto condiviso, l’analisi statica può mostrare quali parti non sono più coerenti.
Questo è uno dei vantaggi più concreti nei progetti che vivono a lungo: TypeScript non serve soltanto a evitare di passare una stringa dove attendevi un numero. Serve a rendere più osservabile l’impatto di un cambiamento.
Curva di apprendimento e complessità del progetto
TypeScript introduce anche lavoro aggiuntivo:
- devi capire JavaScript;
- devi imparare il modello dei tipi;
- devi gestire configurazione e dipendenze;
- puoi incontrare incompatibilità tra librerie, build tool e versioni;
- tipi molto sofisticati possono diventare difficili da leggere quanto il codice che cercano di descrivere.
Per questo “TypeScript è sempre meglio” è una conclusione debole. La scelta va collegata al costo reale della codebase.
I vantaggi reali di TypeScript
I vantaggi più importanti emergono quando il codice viene modificato, condiviso e mantenuto nel tempo.
Intercettare incoerenze prima dell’esecuzione
Un contratto esplicito può bloccare molte combinazioni impossibili prima che raggiungano produzione.
Se una funzione accetta un oggetto Ordine, non devi ricordare ogni volta a memoria quali campi siano richiesti. Il compilatore può aiutarti a verificare chiamate e assegnazioni.
Non elimina il testing, ma sposta parte della verifica strutturale dentro il normale ciclo di sviluppo.
Rendere espliciti i contratti tra parti del software
In un programma reale i dati attraversano moduli, componenti, servizi e funzioni.
Un tipo può descrivere:
interface RisultatoRicerca {
id: string;
titolo: string;
url: string;
}
Quella struttura diventa un contratto tecnico tra produttore e consumatore del dato. Quando cambia, il type checker può aiutare a individuare quali punti devono essere aggiornati.
Refactoring più sicuro nelle codebase grandi
Il refactoring non significa semplicemente “pulire il codice”. Significa modificarne la struttura preservandone il comportamento atteso.
Più una codebase è collegata internamente, più una modifica apparentemente semplice può propagarsi.
TypeScript aumenta la quantità di informazioni disponibili agli strumenti e rende molte di queste dipendenze visibili immediatamente. È qui che il costo iniziale dei tipi può restituire valore nel tempo.
Migliorare collaborazione e comprensione del codice
Un tipo ben progettato funziona anche come documentazione eseguibile dal compilatore.
type StatoOrdine = "nuovo" | "pagato" | "spedito" | "annullato";
È molto più informativo di una stringa generica perché limita esplicitamente gli stati ammessi.
Il vantaggio, però, dipende dalla qualità della modellazione. Un progetto pieno di any, assertion e tipi incomprensibili può perdere gran parte del beneficio.
I limiti di TypeScript che bisogna conoscere
Una guida utile a TypeScript deve spiegare anche dove smette di proteggerti.
Type safety non significa validazione dei dati runtime
Supponiamo di ricevere un utente da una API:
type Utente = {
id: number;
nome: string;
};
E poi:
const risposta = await fetch("/api/utente/1");
const dati = (await risposta.json()) as Utente;
L’assertion as Utente non verifica il contenuto della risposta. Stai dicendo al compilatore di trattare quel valore come Utente; non stai controllando che il server abbia realmente restituito un numero in id e una stringa in nome.
Lo stesso vale per dati letti da file, local storage, form e altri confini esterni. Un documento JSON può essere sintatticamente valido ma avere una struttura diversa da quella attesa dalla tua applicazione.
Per i dati non affidabili serve una validazione runtime: controlli scritti da te oppure una libreria progettata per validare e trasformare input reali.
Questa distinzione è essenziale:
TypeScript descrive e verifica assunzioni statiche ≠ validare ciò che arriva realmente a runtime
any, assertion e configurazioni permissive possono aggirare i controlli
Questo codice disattiva di fatto gran parte del vantaggio:
let valore: any = "ciao"; valore.funzioneCheNonEsiste();
Anche una assertion può costringere il compilatore ad accettare un’ipotesi che non hai verificato.
const elemento = document.querySelector("#prezzo") as HTMLInputElement;
Se l’elemento non esiste, TypeScript non lo materializzerà nel DOM. Hai soltanto dichiarato al type checker una maggiore certezza di quella che il runtime possiede.
Tipi complessi possono aumentare il costo di sviluppo
Un sistema di tipi potente invita a modellare molto.
A volte è corretto. Altre volte si finisce a costruire tipi condizionali, generics annidati e utility difficili da decifrare per evitare poche righe di codice più semplice.
Il criterio pratico è: il tipo riduce davvero ambiguità e rischio, oppure sta diventando un secondo programma da mantenere?
La sofisticazione del type system non è un obiettivo in sé.
Quando TypeScript può essere eccessivo
Per uno script usa-e-getta, una piccola automazione, un prototipo temporaneo o poche righe isolate, introdurre configurazione e build può avere un ritorno limitato.
Questo non significa che TypeScript sia inadatto ai piccoli progetti. Un progetto piccolo ma destinato a crescere, mantenuto da più persone o integrato con molte API può beneficiarne fin dall’inizio.
La dimensione è solo un segnale. Conta soprattutto il costo degli errori e dei cambiamenti.
Dove viene usato TypeScript
TypeScript segue JavaScript nei principali ambienti in cui viene sviluppato software con l’ecosistema JavaScript.
Applicazioni front-end e framework
Nel browser TypeScript viene utilizzato per componenti, stato, chiamate di rete e logica dell’interfaccia. I tipi delle Web API aiutano inoltre l’editor a comprendere oggetti come Document, Element, Event e molte altre interfacce esposte dalla piattaforma.
Per capire dove finisce il linguaggio e dove iniziano le API del browser è utile conoscere il DOM, Document Object Model: TypeScript può descriverne i tipi, ma il DOM viene fornito dall’ambiente browser, non dal linguaggio TypeScript.
Framework e librerie moderni possono integrare TypeScript in modi differenti. Prima di copiare una configurazione, conviene quindi verificare la documentazione specifica dello stack utilizzato.
Backend e Node.js
TypeScript è molto diffuso anche nel backend JavaScript.
In un progetto Node puoi utilizzarlo con una toolchain completa oppure, nelle versioni moderne del runtime, eseguire direttamente file TypeScript che usano soltanto sintassi eliminabile tramite il supporto nativo di type stripping.
La distinzione è importante: il supporto nativo di Node non equivale al type checking completo, non applica l’intero tsconfig.json e non sostituisce automaticamente il compilatore o gli strumenti di build quando il progetto richiede trasformazioni e controlli più avanzati. La documentazione Node dedicata a TypeScript mantiene aggiornati questi limiti.
Progetti full-stack
TypeScript diventa particolarmente interessante quando front-end e backend condividono modelli, pacchetti o contratti.
Un team può usare lo stesso ecosistema di tipi per descrivere oggetti applicativi, payload, errori e interfacce tra livelli. Questo non rende browser e server equivalenti: cambiano runtime, API disponibili, sicurezza e responsabilità.
È il motivo per cui, in un percorso da Full Stack Developer, usare JavaScript o TypeScript su entrambi i lati può ridurre il numero di linguaggi da gestire senza eliminare la necessità di capire le differenze tra client e server.
API, librerie e codebase condivise
Le librerie possono distribuire dichiarazioni di tipo che descrivono la loro API pubblica. Questo permette agli editor e al compilatore di conoscere firme, opzioni e valori restituiti anche quando il codice della libreria verrà eseguito come JavaScript.
Nelle codebase condivise i tipi diventano particolarmente utili ai confini: ciò che un modulo espone, ciò che un servizio riceve, ciò che una funzione restituisce.
La regola resta però invariata: appena il dato supera un confine non controllato — rete, input utente, database, file — la validazione runtime torna necessaria.
TypeScript e JavaScript: quale scegliere
La scelta corretta non è “linguaggio moderno contro linguaggio vecchio”. TypeScript dipende da JavaScript e non rende inutili le sue fondamenta.
Quando partire direttamente con TypeScript
TypeScript ha spesso molto senso quando:
- il progetto dovrà essere mantenuto a lungo;
- più sviluppatori lavorano sulla stessa codebase;
- esistono molti modelli di dati condivisi;
- il refactoring è frequente;
- front-end e backend condividono contratti;
- una libreria o un framework lo integra bene;
- il costo di un errore strutturale è superiore al costo della configurazione iniziale.
In questi casi partire tipizzati può evitare una migrazione successiva e rendere subito espliciti i confini principali.
Quando JavaScript può essere sufficiente
JavaScript può essere la scelta più semplice quando:
- stai studiando le fondamenta del linguaggio;
- il codice è molto piccolo e temporaneo;
- stai creando uno script con vita breve;
- la toolchain TypeScript aggiungerebbe più lavoro di quanto ne risparmi;
- il team non possiede ancora le competenze necessarie per modellare i tipi senza trasformarli in attrito.
Anche in JavaScript puoi comunque ottenere parte del supporto dei tipi attraverso JSDoc e strumenti che utilizzano il motore di analisi TypeScript. L’adozione non deve essere per forza tutto-o-niente.
Decision matrix: progetto, team e manutenzione
| Scenario | Scelta iniziale più sensata | Perché |
|---|---|---|
| Imparare JavaScript da zero | JavaScript | Prima serve capire linguaggio e runtime |
| Script molto breve e temporaneo | JavaScript | Il costo della configurazione può superare il beneficio |
| Applicazione destinata a crescere | TypeScript | I contratti diventano utili con l’aumento delle dipendenze |
| Team con più developer | TypeScript | Riduce ambiguità tra moduli e facilita refactoring |
| Libreria pubblica | TypeScript o dichiarazioni di tipo curate | L’API tipizzata migliora consumo e tooling |
| Dati esterni poco affidabili | TypeScript + validazione runtime | I tipi statici da soli non verificano l’input reale |
| Migrazione di una codebase JS grande | Adozione graduale | Permette di tipizzare i confini più importanti senza riscrivere tutto |
Il verdetto è quindi condizionale: scegli TypeScript quando il valore della maggiore informazione supera il costo aggiuntivo della toolchain e della modellazione.
Come iniziare con TypeScript
Per imparare non serve partire da un framework.
Provare TypeScript senza installare nulla con il Playground
Il TypeScript Playground ufficiale permette di scrivere codice, vedere gli errori del type checker e osservare il JavaScript prodotto senza configurare un progetto locale.
È il modo più veloce per sperimentare con annotazioni, union, narrowing e generics.
Prova per esempio:
function quadrato(valore: number) {
return valore * valore;
}
quadrato(4);
quadrato("4");
L’editor evidenzierà la seconda chiamata come incompatibile.
Installare TypeScript in un progetto
Con Node.js e npm disponibili puoi inizializzare un progetto e installare TypeScript come dipendenza di sviluppo:
npm init -y npm install -D typescript
Verifica la versione:
npx tsc --version
Poi genera una configurazione iniziale:
npx tsc --init
La configurazione generata dipende dalla versione corrente di TypeScript. Leggila prima di modificarla: non trattare tsconfig.json come un file da copiare invariato tra Node, browser, framework e librerie.
Creare una configurazione tsconfig.json
Per capire la struttura, ecco un esempio volutamente ridotto:
{
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "ESNext",
"outDir": "dist"
},
"include": ["src"]
}
strict abilita una famiglia di controlli più rigorosi. target indica il livello JavaScript che vuoi produrre; module riguarda il sistema di moduli; outDir definisce la cartella di output.
Non esiste però una configurazione universale “migliore”. Se stai usando Node, Vite, Next.js, Angular o un altro ambiente, parti dalla documentazione dello stack.
Compilare ed eseguire il primo file
Crea:
src/index.ts
con:
function somma(a: number, b: number): number {
return a + b;
}
console.log(somma(2, 3));
Poi esegui:
npx tsc
Se la configurazione prevede l’emit, nella cartella di output troverai il JavaScript prodotto.
Il passaggio importante non è il comando. È osservare cosa resta e cosa scompare: la logica JavaScript resta, le annotazioni di tipo no.
Migrare gradualmente un progetto JavaScript esistente
Una migrazione non deve iniziare rinominando migliaia di file nello stesso commit.
Un percorso più controllabile è:
- introdurre il tooling TypeScript;
- verificare compatibilità della build;
- iniziare dai moduli con confini chiari;
- tipizzare API interne e strutture condivise;
- ridurre gradualmente
anye assertion non necessarie; - aumentare il livello di strictness quando la codebase è pronta;
- mantenere test e validazione runtime sui confini esterni.
L’obiettivo non è arrivare al “100% di tipi” come metrica decorativa. È ottenere abbastanza informazione da rendere il codice più semplice da modificare con sicurezza.
TypeScript oggi: cosa è cambiato con la toolchain nativa
La parte più recente dell’evoluzione di TypeScript riguarda soprattutto la velocità e l’architettura degli strumenti, non un nuovo modello di runtime per il linguaggio.
TypeScript 7 e il compiler nativo scritto in Go
La release stabile corrente è TypeScript 7.0. Il progetto ha portato la toolchain principale su una nuova implementazione nativa in Go, progettata per sfruttare codice nativo, memoria condivisa e parallelizzazione.
Microsoft indica, nei propri benchmark ufficiali su grandi codebase open source, miglioramenti tipici nell’ordine di circa 8×–12× sui full build rispetto alla generazione precedente. È un dato del vendor su codebase e hardware specifici: non significa che ogni progetto sarà dieci volte più veloce. La release note ufficiale di TypeScript 7 pubblica i benchmark e i limiti della transizione.
Perché la velocità del type checker conta nei progetti grandi
In una codebase piccola, passare da un controllo rapido a uno ancora più rapido può essere quasi impercettibile.
Nei monorepo e nei progetti con migliaia di file, invece, type checking, build, CI e language server entrano nel ciclo di lavoro decine di volte al giorno. Ridurre la latenza può cambiare concretamente:
- quanto velocemente compaiono gli errori nell’editor;
- quanto dura una pipeline CI;
- quanto costa eseguire controlli frequenti;
- quanto spesso gli sviluppatori evitano un check perché troppo lento.
Il vantaggio della toolchain nativa è quindi soprattutto operativo: rende più sostenibile applicare controlli statici su codebase molto grandi.
Compatibilità e differenza tra TypeScript 6 e 7
TypeScript 7 mira a mantenere compatibile il comportamento del type checker e della CLI rispetto a TypeScript 6, ma la transizione non è completamente invisibile.
La release corrente non espone ancora la stessa API programmatica storicamente usata da alcuni strumenti. Inoltre flussi che incorporano profondamente TypeScript in compiler e language service esterni possono avere tempi di adozione differenti.
Questo significa che l’aggiornamento va verificato sullo stack reale. Se un progetto usa framework, plugin o tool che dipendono dall’API del compilatore, controllare la compatibilità è più importante che inseguire immediatamente il numero di versione più recente.
Domande frequenti su TypeScript
Bisogna conoscere JavaScript prima di TypeScript?
Sì, almeno le fondamenta.
TypeScript aggiunge un sistema di tipi, ma eredita sintassi, runtime behavior, funzioni, oggetti, Promise, moduli e gran parte del modello mentale da JavaScript. Anche il TypeScript Handbook consiglia a chi non conosce JavaScript di costruire prima quelle basi.
Imparare TypeScript senza capire JavaScript porta facilmente ad attribuire al type checker problemi che appartengono invece al linguaggio o al runtime.
Il browser può eseguire direttamente TypeScript?
In generale, il browser esegue JavaScript e WebAssembly secondo le funzionalità che supporta; la sintassi TypeScript viene normalmente rimossa o trasformata dalla toolchain prima della distribuzione.
Il punto importante è non progettare l’applicazione assumendo che le annotazioni di tipo esistano nel browser a runtime. Le informazioni statiche non diventano controlli automatici sui valori reali.
Node.js può eseguire TypeScript?
Le versioni moderne di Node.js possono eseguire direttamente file TypeScript che utilizzano sintassi eliminabile attraverso il type stripping nativo.
Questo supporto, però, non esegue type checking e ignora tsconfig.json per le funzionalità che dipendono dalla trasformazione. Per una toolchain TypeScript completa continuano quindi a essere utili il compilatore o strumenti dedicati, in base al progetto.
TypeScript è un linguaggio compilato o transpilato?
Nel linguaggio comune si usano entrambi i termini, ma è più utile concentrarsi sul processo.
Il tool TypeScript analizza il programma, verifica i tipi e può emettere JavaScript compatibile con il target configurato. Chiamarlo “transpilazione” sottolinea che l’output resta un linguaggio di livello simile; “compilazione” è il termine utilizzato anche dalla documentazione e dagli strumenti TypeScript.
Nella pratica, ciò che conta è distinguere type checking, trasformazione ed esecuzione.
TypeScript sostituisce JavaScript?
No.
TypeScript si basa sull’ecosistema e sul comportamento JavaScript. Il codice distribuito viene normalmente eseguito in runtime JavaScript e uno sviluppatore TypeScript deve comunque comprendere come funziona JavaScript.
Pensarlo come sostituto porta a un apprendimento fragile; pensarlo come un livello di analisi e tooling sopra JavaScript è molto più utile.
TypeScript è utile anche nei progetti piccoli?
Può esserlo.
Un progetto piccolo ma duraturo, condiviso da più persone o ricco di integrazioni può beneficiare molto dei tipi. Uno script temporaneo di poche righe può invece non giustificare una toolchain aggiuntiva.
La domanda corretta non è “quante righe ha il progetto?”, ma quanto costano ambiguità, errori e cambiamenti nel suo ciclo di vita?
Conclusione
TypeScript ha senso quando smetti di considerarlo come “JavaScript con tipi” e inizi a vederlo come un sistema per rendere esplicite e verificabili molte delle assunzioni presenti nel codice.
Il vantaggio più importante non è scrivere : string accanto a una variabile. È permettere a editor, compiler e sviluppatori di ragionare su relazioni che in JavaScript resterebbero implicite: quali valori entrano in una funzione, quali proprietà deve avere un oggetto, quali casi sono ammessi e quali parti del progetto vengono coinvolte da un cambiamento.
La contropartita è reale. Devi conoscere JavaScript, mantenere una toolchain, scegliere un livello di strictness sensato e resistere alla tentazione di trasformare il type system in esercizio di sofisticazione. Soprattutto, devi ricordare che i tipi statici non validano i dati esterni e non eliminano gli errori runtime.
Se stai costruendo un percorso professionale da web developer, imparerei prima bene JavaScript e poi introdurrei TypeScript attraverso un progetto concreto: una piccola applicazione con componenti, chiamate API e dati tipizzati. È il contesto in cui diventa immediatamente chiaro cosa il linguaggio ti sta dando — e cosa, invece, continua a essere responsabilità del runtime e del tuo codice.