TypeScript è JavaScript con un sistema di tipi statico aggiunto sopra. Ogni programma JavaScript è sintassi TypeScript valida; TypeScript aggiunge le annotazioni di tipo, un compilatore che le controlla prima che il codice venga eseguito e un passaggio di build che le rimuove di nuovo. A runtime c'è solo JavaScript, quindi la differenza sta tutta in ciò che scopri prima di pubblicare.
In JavaScript la stessa funzione è il codice senza type Product = ..., : Product[] e : number. I tipi aggiungono informazioni per il compilatore e per l'editor; non cambiano ciò che fa il programma.
TypeScript vs JavaScript a colpo d'occhio
| JavaScript | TypeScript | |
|---|---|---|
| Sistema di tipi | Dinamico: i tipi appartengono ai valori e si conoscono solo a runtime | Statico: i tipi sono dichiarati o dedotti e controllati in fase di compilazione |
| Quando emergono gli errori di tipo | Quando la riga viene eseguita (undefined, NaN, TypeError) | Nell'editor mentre scrivi, e quando compili |
| Gira in | Browser, Node.js, Deno, Bun, direttamente | Gli stessi ambienti, dopo la rimozione dei tipi |
| Passaggio di build | Non serve | tsc o un bundler, oppure un runtime che rimuove i tipi da solo |
| File | .js, .mjs, .cjs | .ts, .mts, .cts, .tsx, più le dichiarazioni di tipo .d.ts |
| Velocità a runtime | Riferimento | Identica: l'output è JavaScript |
| Supporto dell'editor | Autocompletamento dai tipi dedotti e dai typing delle librerie, che possono essere incompleti | Autocompletamento, rinomina e "trova tutti i riferimenti" dai tipi dichiarati |
| Curva di apprendimento | Più bassa | JavaScript più il sistema di tipi |
| Standard | ECMAScript, di TC39 | Un progetto open source di Microsoft che segue ECMAScript |
Lo stesso codice nei due linguaggi
Ecco una funzione in JavaScript. Niente al suo interno dice come deve essere fatto user:
function greeting(user) {
return `Hello, ${user.firstName} ${user.lastName}`;
}
greeting({ firstname: "Ada", lastName: "Lovelace" });
// "Hello, undefined Lovelace", no error anywhere
La versione TypeScript dichiara la forma una volta, e l'errore di battitura viene segnalato prima che il codice venga eseguito:
interface User {
firstName: string;
lastName: string;
}
function greeting(user: User): string {
return `Hello, ${user.firstName} ${user.lastName}`;
}
greeting({ firstname: "Ada", lastName: "Lovelace" });
// error TS2561: Object literal may only specify known properties,
// but 'firstname' does not exist in type 'User'. Did you mean to write 'firstName'?
Le annotazioni sono l'intera differenza di sintassi. TypeScript aggiunge anche alcune dichiarazioni proprie (interface, type, enum, generics come Array<string>, modificatori di accesso come private), ma istruzioni, operatori e oggetti integrati sono quelli di JavaScript.
Cosa intercetta TypeScript e JavaScript no
JavaScript converte i tipi in silenzio. Questo bug è comune con i valori che arrivano dai campi di un form, che sono sempre stringhe. Eseguilo per vedere cosa dice il compilatore:
index.ts(7,17): error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'number[]'.
Type 'string' is not assignable to type 'number'.
In JavaScript questo codice viene eseguito e stampa 010205, perché 0 + "10" è una concatenazione di stringhe. TypeScript si rifiuta di compilare finché le stringhe non vengono convertite, per esempio con fromForm.map(Number).
L'altra grande categoria sono i valori che potrebbero mancare. Array.prototype.find restituisce undefined quando nessun elemento corrisponde, e TypeScript ti obbliga a gestire il caso:
index.ts(8,13): error TS18048: 'user' is possibly 'undefined'.
La versione in semplice JavaScript va in crash a runtime con TypeError: Cannot read properties of undefined (reading 'name'). La soluzione in TypeScript è gestire il caso indicato dal compilatore:
Output:
GRACE
no user with id 3
Cosa TypeScript non intercetta: gli errori di logica (una formula sbagliata ha il tipo giusto) e tutto ciò che riguarda i dati che entrano nel programma a runtime. Una risposta di un'API tipizzata come User è corretta solo quanto il server che l'ha inviata, perché i tipi spariscono quando il codice viene eseguito. Controlla questi dati con codice a runtime.
Usare librerie JavaScript in TypeScript
Ogni pacchetto npm funziona da TypeScript, perché l'output è comunque JavaScript. I tipi di un pacchetto arrivano da uno di tre posti:
- Il pacchetto include i propri file
.d.ts. La maggior parte dei pacchetti mantenuti attivamente lo fa, e non devi installare nient'altro. - Un pacchetto
@typesseparato del progetto comunitario DefinitelyTyped:npm install --save-dev @types/lodashaggiunge i tipi perlodash. - Da nessuna parte. In quel caso, con
strictattivo, l'import stesso è un errore:
error TS7016: Could not find a declaration file for module 'lodash'. '/project/node_modules/lodash/lodash.js' implicitly has an 'any' type.
Try `npm i --save-dev @types/lodash` if it exists or add a new declaration (.d.ts) file containing `declare module 'lodash';`
La soluzione è installare il pacchetto @types, se esiste, oppure descrivere tu il modulo in un file .d.ts; la pagina sui declaration file mostra come.
Il passaggio di build
Browser e Node.js non controllano i tipi, quindi TypeScript ha bisogno di un passaggio tra il tuo sorgente e il codice che viene eseguito. Ci sono tre configurazioni comuni:
tsccompila tutto. Controlla i tipi e scrive i file.js, di solito in una cartelladist. Semplice, ed è lo standard per le librerie.- Un bundler o un dev server rimuove i tipi, e
tsc --noEmitli controlla. Vite ed esbuild eliminano i tipi senza controllarli, così i ricaricamenti restano rapidi; il type checker lo eseguono l'editor e un passaggio della CI. - Il runtime rimuove i tipi. Le versioni attuali di Node.js, Deno e Bun eseguono direttamente i file
.ts. Nessuno di loro controlla i tipi durante l'esecuzione, quinditsc --noEmit(odeno check) resta il modo per trovare gli errori di tipo.
JavaScript non ha bisogno di nulla di tutto questo, ed è il suo vantaggio pratico più grande per gli script piccoli. Il costo del passaggio TypeScript è soprattutto la configurazione, un tsconfig.json e una dipendenza di sviluppo typescript, più il tempo di compilazione; il compilatore nativo di TypeScript 7 ha ridotto quel tempo di circa dieci volte sui progetti grandi.
Curva di apprendimento
Tutto ciò che sai di JavaScript resta valido, perché il runtime di TypeScript è JavaScript. La parte nuova è il sistema di tipi, e si impara a livelli:
- Annotazioni su variabili, parametri e valori di ritorno (
: string,: number[]). - Tipi oggetto con
interfaceetype, proprietà opzionali, union comestring | number. - Narrowing: controllare un valore con
typeof,ino===in modo che il compilatore sappia in quale caso ti trovi. - Generics, utility type come
Partial<T>ePick<T, K>, e tipi avanzati per chi scrive librerie.
I primi due livelli coprono la maggior parte del codice applicativo. Buona parte dei tipi viene dedotta, quindi molto codice TypeScript sembra JavaScript con annotazioni solo sulle firme delle funzioni.
Quando scegliere TypeScript o JavaScript
TypeScript è meglio di JavaScript? Per il codice mantenuto da più persone o che dura anni, di solito sì, e il settore si è mosso in quella direzione: secondo il conteggio dei contributori mensili di GitHub, ad agosto 2025 TypeScript ha superato sia JavaScript sia Python diventando il linguaggio più usato su GitHub. Per gli script piccoli, il semplice JavaScript è spesso lo strumento migliore.
Scegli TypeScript quando:
- Sul codice lavora più di una persona, o verrà mantenuto per mesi o anni.
- La codebase è abbastanza grande da non poter tenere a mente tutte le firme delle funzioni.
- Fai refactoring spesso: rinominare una proprietà aggiorna ogni suo uso, e il compilatore elenca tutto ciò che resta indietro.
- Pubblichi una libreria: i file
.d.tsdanno a chi la usa autocompletamento e controlli. - Il framework se lo aspetta. Le app Angular si scrivono in TypeScript, Next.js e Astro creano i nuovi progetti in TypeScript di default, e i template React, Vue e Svelte di Vite hanno ciascuno una variante TypeScript.
Scegli JavaScript quando:
- Il programma è uno script breve, un esperimento occasionale o un frammento di codice nella console del browser.
- Stai imparando a programmare per la prima volta e vuoi meno concetti tutti insieme.
- Non c'è un passaggio di build e non ne vuoi uno. Anche in quel caso,
// @ts-checkcon JSDoc ti dà qualche controllo in un semplice file.js.
Migrare un progetto JavaScript a TypeScript
Una migrazione non deve avvenire tutta in una volta. Il compilatore accetta JavaScript accanto a TypeScript:
{
"compilerOptions": {
"allowJs": true,
"checkJs": false,
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"]
}
Con allowJs, i file .js vengono compilati e possono importare dai file .ts e viceversa. Poi converti un po' alla volta:
- Rinomina un file da
.jsa.tse correggi gli errori che il compilatore segnala al suo interno. - Parti dalle foglie (moduli di utilità con pochi import), poi procedi verso l'interno.
- Attiva
checkJs, o aggiungi// @ts-checkin cima ai singoli file.js, per controllare i tipi dei file che non hai ancora rinominato.
Nei file JavaScript controllati, i tipi li forniscono i commenti JSDoc:
// @ts-check
/**
* @param {number} price
* @param {number} qty
* @returns {number}
*/
function lineTotal(price, qty) {
return price * qty;
}
lineTotal("3", 2);
// error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
Alcuni team si fermano qui: file JavaScript con tipi JSDoc, controllati da tsc, e nessun passaggio di build per il codice stesso. Altri arrivano fino a .ts. Se attivi strict in un progetto esistente, aspettati molti errori all'inizio; la pagina sullo strict mode elenca cosa controlla ogni flag, così puoi attivarli uno alla volta.
Domande frequenti
Qual è la differenza principale tra TypeScript e JavaScript?
TypeScript aggiunge i tipi statici a JavaScript. Descrivi cos'è ogni valore (name: string, items: Item[]) e il compilatore TypeScript segnala gli errori prima che il codice venga eseguito. JavaScript non controlla nulla in anticipo: un tipo sbagliato emerge solo quando quella riga viene eseguita, spesso come undefined o come TypeError.
TypeScript è meglio di JavaScript?
Per la maggior parte dei progetti mantenuti da più di una persona, o che durano più di qualche settimana, sì: i tipi intercettano intere categorie di bug, rendono sicuro il refactoring e alimentano l'autocompletamento dell'editor. Per uno script breve, un prototipo veloce o un esercizio di apprendimento, il semplice JavaScript è più rapido da avviare e non richiede alcuna configurazione di build.
TypeScript è più veloce di JavaScript?
No, e non è nemmeno più lento. TypeScript viene compilato in JavaScript e i tipi vengono eliminati, quindi il codice eseguito è lo stesso JavaScript che scriveresti a mano. L'unico costo in più è il tempo di compilazione durante lo sviluppo.
Devo imparare prima JavaScript o TypeScript?
Impara le basi di JavaScript prima di TypeScript o insieme a esso. Tutto il comportamento a runtime (variabili, funzioni, oggetti, array, promise) è JavaScript, e TypeScript si limita a descriverlo. Quando sai scrivere piccoli programmi in JavaScript, aggiungere i tipi è un passo breve.
Posso usare TypeScript e JavaScript nello stesso progetto?
Sì. Imposta "allowJs": true in tsconfig.json e il compilatore accetta file .js accanto ai file .ts. Aggiungi "checkJs": true (o un commento // @ts-check per file) per controllare i tipi anche nei file JavaScript, usando i tipi dei commenti JSDoc. È il modo abituale per migrare un progetto un file alla volta.