tsconfig.json è il file di configurazione di un progetto TypeScript. Quando esegui tsc senza argomenti, il compilatore lo cerca nella cartella corrente (poi nelle cartelle superiori), legge le opzioni in compilerOptions e controlla i file elencati da include. Eccone uno piccolo ma completo:
{
"compilerOptions": {
"target": "es2022",
"module": "nodenext",
"strict": true,
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}
Questo compila ogni file TypeScript in src in JavaScript dentro dist, come codice ES2022, con le regole dei moduli di Node.js e tutti i controlli strict attivi. npx tsc --init genera un file iniziale più lungo, con un commento su ogni opzione.
Il file è JSON con commenti: sono accettati i commenti //, i commenti /* */ e le virgole finali.
Una configurazione iniziale consigliata
Per un'applicazione o uno script Node.js:
{
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"target": "es2024",
"lib": ["es2024"],
"module": "nodenext",
"types": ["node"],
"strict": true,
"noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"sourceMap": true
},
"include": ["src"]
}
Serve npm install --save-dev @types/node per i tipi di Node.js. Con module: "nodenext", il campo "type" in package.json decide se un file .ts è un modulo ES ("type": "module") o CommonJS ("type": "commonjs", che è ciò che scrive npm init -y). Usa "type": "module" per i nuovi progetti che usano import ed export.
Per il codice costruito da un bundler come Vite, esbuild o webpack, è il bundler a scrivere il JavaScript e tsc si limita a controllare:
{
"compilerOptions": {
"target": "es2022",
"lib": ["es2022", "dom"],
"module": "preserve",
"noEmit": true,
"strict": true,
"noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"skipLibCheck": true,
"jsx": "react-jsx"
},
"include": ["src"]
}
I template dei framework (Vite, Next.js, Angular) generano il proprio tsconfig.json. Parti dal loro invece di sostituirlo.
Le opzioni che contano
| Opzione | Cosa fa | Valore predefinito in TypeScript 7 |
|---|---|---|
target | Versione di JavaScript dell'output; la sintassi più recente viene riscritta per i target più vecchi | es2025 |
lib | Tipi delle API integrate che il checker conosce (Array.prototype.at, Map, document) | Segue target, più il DOM |
module | Tipo di codice di modulo emesso e regole dei moduli applicate | esnext |
moduleResolution | Come vengono trovati sul disco i percorsi di import | nodenext o node16 con il module corrispondente, altrimenti bundler |
strict | Attiva l'intera famiglia di controlli strict | true |
rootDir | Cartella la cui struttura viene riprodotta in outDir | La cartella che contiene tsconfig.json |
outDir | Dove finiscono i file .js (e .d.ts) | Accanto a ogni file sorgente |
include / exclude / files | Quali file fanno parte del progetto | Ogni file .ts nella cartella |
types | Quali pacchetti @types vengono caricati senza import | [], nessuno |
noEmit | Solo controllo, non scrive nulla | false |
declaration | Scrive anche i file di dichiarazione dei tipi .d.ts | false |
sourceMap | Scrive file .js.map per i debugger | false |
esModuleInterop | Fa funzionare import x from "cjs-package" con i pacchetti CommonJS | true (non si può disattivare) |
skipLibCheck | Salta il controllo dei tipi dei file .d.ts, compresi quelli in node_modules | false |
target e lib
target dice su quale versione di JavaScript deve girare l'output. La sintassi più recente del target viene riscritta: con "target": "es2017", un campo di classe o ??= diventa codice più vecchio. Il target più basso che TypeScript 7 accetta è es2015 (es6); es5 è stato rimosso.
target non aggiunge le API di runtime mancanti. Descriverle è compito di lib, fornirle è compito di un polyfill. lib dice al checker quali oggetti e metodi integrati esistono. Il suo valore predefinito segue target e include anche i tipi DOM del browser, quindi document supera il controllo dei tipi anche in un progetto Node.js, a meno che tu non imposti lib. Usare un metodo di uno standard più recente della tua lib è un errore di compilazione:
src/b.ts(1,24): error TS2550: Property 'toSorted' does not exist on type 'number[]'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2023' or later.
Gli esempi eseguibili di questa documentazione usano la lib es2022, quindi toSorted, Object.groupBy e i nuovi metodi di Set non sono disponibili.
module e moduleResolution
module ha tre valori sensati per il codice nuovo:
nodenext: per il codice eseguito da Node.js. Ogni file è ESM o CommonJS in base alla sua estensione (.mts,.cts) o al"type"delpackage.jsonpiù vicino, esattamente come decide Node. Gli import relativi nei moduli ES richiedono un'estensione, scritta come.jsanche se il sorgente è.ts:import { add } from "./math.js".moduleResolutionsi adegua in automatico.preserve: per il codice elaborato da un bundler. Gli import restano come sono scritti e la risoluzione usa le regolebundler, che ammettono import senza estensione.esnext: output come semplici moduli ES, con risoluzionebundler. È il valore predefinito quandomodulenon è impostato.
Un primo errore frequente con la configurazione di tsc --init nasce dal fatto che npm init -y scrive "type": "commonjs":
src/main.ts(1,10): error TS1295: ECMAScript imports and exports cannot be written in a CommonJS file under 'verbatimModuleSyntax'.
Il file usa import, ma package.json dice che il progetto è CommonJS. Cambia "type" in "module". La pagina sui moduli tratta import ed export nel dettaglio.
strict e le opzioni di controllo
"strict": true attiva in un colpo solo un gruppo di controlli: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, strictBuiltinIteratorReturn, noImplicitThis e useUnknownInCatchVariables. È il valore predefinito in TypeScript 7 ed è attivo in ogni esempio eseguibile di queste pagine. Il codice scritto per lo strict mode restringe il tipo prima di usare un valore che potrebbe mancare:
Senza un'annotazione, il tipo di un parametro non si può dedurre, e noImplicitAny lo segnala:
index.ts(2,17): error TS7006: Parameter 'n' implicitly has an 'any' type.
strict non include tutti i controlli utili. Due che vale la pena aggiungere sono noUncheckedIndexedAccess (un elemento di array o una lettura tramite index signature ha tipo T | undefined) e exactOptionalPropertyTypes (a una proprietà opzionale non si può assegnare esplicitamente undefined); tsc --init li attiva entrambi. I controlli di stile come noUnusedLocals, noImplicitReturns e noFallthroughCasesInSwitch sono disattivati di default.
Quali file: include, exclude, rootDir, outDir
Senza include o files, il progetto contiene ogni file .ts, .tsx e .d.ts della cartella e delle sue sottocartelle. node_modules resta sempre fuori. Anche outDir resta fuori, ma solo finché non imposti exclude: una lista exclude personalizzata sostituisce quella predefinita, quindi aggiungici la cartella di output. include ed exclude accettano pattern glob:
{
"include": ["src", "scripts/**/*.ts"],
"exclude": ["src/**/*.test.ts"]
}
exclude filtra solo ciò che include ha trovato. Un file importato da un altro file incluso viene comunque compilato.
outDir è dove va l'output, e rootDir è la parte dell'albero dei sorgenti che viene riprodotta al suo interno: con "rootDir": "./src", src/api/users.ts diventa dist/api/users.js. Impostali entrambi. rootDir vale di default la cartella che contiene tsconfig.json, quindi se imposti solo outDir mentre i sorgenti stanno in src, TypeScript 7 si ferma con:
error TS5011: The common source directory of 'tsconfig.json' is './src'. The 'rootDir' setting must be explicitly set to this or another path to adjust your output's file layout.
Opzioni di output: noEmit, declaration, sourceMap
"noEmit": truefa ditscun puro type checker. Usalo quando un altro strumento (un bundler,tsx, il type stripping di Node.js) produce il JavaScript."declaration": truescrive un file.d.tsper modulo, i tipi senza il codice. Le librerie ne hanno bisogno perché i loro utenti ricevano i tipi.declarationMapaggiunge le mappe per il "vai alla definizione" verso il sorgente.ts."sourceMap": truescrive i file.js.map, così debugger e stack trace puntano alle righe del.ts."noEmitOnError": truenon scrive nulla finché ci sono errori di tipo. Senza questa opzione,tscsegnala gli errori e scrive comunque il JavaScript.
types, esModuleInterop e skipLibCheck
types elenca i pacchetti @types caricati globalmente, senza import. Il valore predefinito di TypeScript 7 è una lista vuota, quindi dopo npm install --save-dev @types/node devi anche aggiungere "types": ["node"]; altrimenti process e require restano sconosciuti (error TS2591: Cannot find name 'process'). Nella stessa lista vanno i test runner con funzioni globali, come il describe di Jest.
esModuleInterop fa funzionare gli import di default dei pacchetti CommonJS (import express from "express"). In TypeScript 7 è sempre attivo, e impostarlo a false è un errore.
skipLibCheck salta il controllo dei tipi dei file di dichiarazione. Velocizza le build ed evita errori dentro node_modules che non puoi correggere, al prezzo di non accorgerti dei conflitti tra i tipi di due librerie. La maggior parte dei progetti lo attiva.
Condividere le impostazioni con extends
extends carica un'altra configurazione e permette a questo file di sovrascriverne alcune parti:
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}
Le compilerOptions vengono unite opzione per opzione, mentre include, exclude e files della base vengono sostituiti, non uniti, se questo file li imposta. I percorsi nel file base sono risolti rispetto al file base stesso. extends accetta anche un pacchetto: il progetto @tsconfig/bases ne pubblica uno per ogni ambiente, per esempio npm install --save-dev @tsconfig/node24 e poi "extends": "@tsconfig/node24/tsconfig.json".
Per vedere le impostazioni finali dopo aver applicato tutti gli extends e i valori predefiniti, esegui:
npx tsc --showConfig
Opzioni rimosse in TypeScript 7
TypeScript 6 ha deprecato queste impostazioni e TypeScript 7 le ha rimosse. Una configurazione che ne usa ancora una fallisce con error TS5108 o TS5102, per esempio Option 'baseUrl' has been removed. Please remove it from your configuration.
| Impostazione rimossa | Usa invece |
|---|---|
"target": "es5" | es2015 o successivo |
"moduleResolution": "node" (node10) o "classic" | nodenext o bundler |
"module": "amd", "umd", "system", "none" | nodenext, esnext o preserve, e un bundler per gli altri formati |
baseUrl | Voci di paths relative al file tsconfig |
outFile | Un bundler |
downlevelIteration | Niente: i target da es2015 in su supportano l'iterazione in modo nativo |
"esModuleInterop": false, "allowSyntheticDefaultImports": false, "alwaysStrict": false | Elimina la riga: sono sempre attive |
La pagina su TypeScript 7 elenca gli altri cambiamenti di quella versione, compresi i nuovi valori predefiniti che questa tabella non copre.
Domande frequenti
Cos'è tsconfig.json?
È il file di configurazione di un progetto TypeScript. La sua presenza indica che la cartella è la radice del progetto, compilerOptions stabilisce come il compilatore controlla e genera il codice, e include, exclude o files dicono quali file fanno parte del progetto. Eseguire tsc senza argomenti lo legge.
Come creo un file tsconfig.json?
Esegui npx tsc --init nella cartella del progetto (con TypeScript installato). Scrive un tsconfig.json con le impostazioni consigliate e un commento su ogni opzione. Puoi anche scrivere il file a mano: {} è un tsconfig valido che usa tutti i valori predefiniti.
Che valore devo dare a target nel tsconfig?
La versione di JavaScript più vecchia su cui il tuo codice deve girare. Per le versioni attuali di Node.js, es2022 o successive vanno bene; il valore predefinito di TypeScript 7 è es2025. target decide quale sintassi più recente viene riscritta per i motori più vecchi e sceglie anche la lib predefinita, l'insieme di API integrate che il checker conosce.
Che differenza c'è tra module e moduleResolution?
module decide che tipo di codice di modulo scrive il compilatore (import/export ES o require CommonJS) e quali regole dei moduli si applicano. moduleResolution decide come un percorso di import come "./utils.js" o "lodash" viene trovato sul disco. Usa nodenext per il codice eseguito da Node.js e module: "preserve" (che implica la risoluzione bundler) per il codice elaborato da un bundler.
tsconfig.json può contenere commenti?
Sì. Il compilatore lo legge come JSON con commenti: sono ammessi i commenti // e /* */ e le virgole finali, ed è per questo che tsc --init scrive un file pieno di opzioni commentate. Altri strumenti che lo leggono come JSON rigoroso possono fallire su questi elementi.