tsconfig.json ist die Konfigurationsdatei eines TypeScript-Projekts. Wenn du tsc ohne Argumente ausführst, sucht der Compiler sie im aktuellen Ordner (danach in den übergeordneten Ordnern), liest die Optionen in compilerOptions und prüft die Dateien, die include auflistet. Eine kleine, aber vollständige Datei:
{
"compilerOptions": {
"target": "es2022",
"module": "nodenext",
"strict": true,
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}
Damit wird jede TypeScript-Datei in src zu JavaScript in dist kompiliert, als ES2022-Code, nach den Modulregeln von Node.js und mit allen strikten Prüfungen. npx tsc --init erzeugt eine längere Startdatei mit einem Kommentar zu jeder Option.
Die Datei ist JSON mit Kommentaren: Kommentare mit // und /* */ sowie abschließende Kommas werden akzeptiert.
Eine empfohlene Startkonfiguration
Für eine Node.js-Anwendung oder ein Skript:
{
"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"]
}
Für die Node.js-Typen brauchst du npm install --save-dev @types/node. Mit module: "nodenext" entscheidet das Feld "type" in package.json, ob eine .ts-Datei ein ES-Modul ("type": "module") oder CommonJS ist ("type": "commonjs", das schreibt npm init -y). Nimm "type": "module" für neue Projekte, die import und export verwenden.
Bei Code, den ein Bundler wie Vite, esbuild oder webpack baut, schreibt der Bundler das JavaScript, und tsc prüft nur:
{
"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"]
}
Framework-Starter (Vite, Next.js, Angular) erzeugen ihre eigene tsconfig.json. Geh von deren Datei aus, statt sie zu ersetzen.
Die wichtigen Optionen
| Option | Was sie bewirkt | Standardwert in TypeScript 7 |
|---|---|---|
target | JavaScript-Version der Ausgabe; neuere Syntax wird für ältere Ziele umgeschrieben | es2025 |
lib | Typen der eingebauten APIs, die der Checker kennt (Array.prototype.at, Map, document) | Passend zu target, plus DOM |
module | Art des ausgegebenen Modulcodes und die geltenden Modulregeln | esnext |
moduleResolution | Wie Importpfade auf der Festplatte gefunden werden | nodenext oder node16 beim passenden module, sonst bundler |
strict | Schaltet die ganze Familie der strikten Prüfungen ein | true |
rootDir | Ordner, dessen Struktur in outDir gespiegelt wird | Der Ordner mit der tsconfig.json |
outDir | Wohin die .js-Dateien (und .d.ts-Dateien) geschrieben werden | Neben jede Quelldatei |
include / exclude / files | Welche Dateien zum Projekt gehören | Jede .ts-Datei unterhalb des Ordners |
types | Welche @types-Pakete ohne Import geladen werden | [], keine |
noEmit | Nur prüfen, nichts schreiben | false |
declaration | Zusätzlich .d.ts-Deklarationsdateien schreiben | false |
sourceMap | .js.map-Dateien für Debugger schreiben | false |
esModuleInterop | Lässt import x from "cjs-package" mit CommonJS-Paketen funktionieren | true (lässt sich nicht ausschalten) |
skipLibCheck | Überspringt die Typprüfung von .d.ts-Dateien, auch in node_modules | false |
target und lib
target gibt an, auf welcher JavaScript-Version die Ausgabe laufen muss. Syntax, die neuer ist als das Ziel, wird umgeschrieben: Mit "target": "es2017" wird aus einem Klassenfeld oder ??= älterer Code. Das niedrigste Ziel, das TypeScript 7 akzeptiert, ist es2015 (es6); es5 wurde entfernt.
target fügt keine fehlenden Laufzeit-APIs hinzu. Sie zu beschreiben ist Aufgabe von lib, sie bereitzustellen Aufgabe eines Polyfills. lib sagt dem Checker, welche eingebauten Objekte und Methoden existieren. Der Standardwert folgt target und enthält auch die DOM-Typen des Browsers, also besteht document die Typprüfung sogar in einem Node.js-Projekt, solange du lib nicht selbst setzt. Eine Methode aus einem neueren Standard als deinem lib zu verwenden, ist ein Compilerfehler:
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.
Die ausführbaren Beispiele in dieser Dokumentation verwenden das es2022-lib, also sind toSorted, Object.groupBy und die neuen Set-Methoden darin nicht verfügbar.
module und moduleResolution
module hat für neuen Code drei sinnvolle Werte:
nodenext: für Code, den Node.js ausführt. Jede Datei ist ESM oder CommonJS, je nach Endung (.mts,.cts) oder dem Feld"type"der nächstenpackage.json, genau wie Node es entscheidet. Relative Imports in ES-Modulen brauchen eine Dateiendung, geschrieben als.js, obwohl die Quelle.tsist:import { add } from "./math.js".moduleResolutionfolgt automatisch.preserve: für Code, den ein Bundler verarbeitet. Imports bleiben, wie sie geschrieben sind, und die Auflösung folgt denbundler-Regeln, die Imports ohne Endung erlauben.esnext: einfache ES-Modul-Ausgabe mitbundler-Auflösung. Das ist der Standard, wennmodulenicht gesetzt ist.
Ein häufiger erster Fehler mit der Konfiguration von tsc --init kommt daher, dass npm init -y den Eintrag "type": "commonjs" schreibt:
src/main.ts(1,10): error TS1295: ECMAScript imports and exports cannot be written in a CommonJS file under 'verbatimModuleSyntax'.
Die Datei verwendet import, aber package.json sagt, das Projekt sei CommonJS. Ändere "type" auf "module". Die Seite zu Modulen behandelt Imports und Exports im Detail.
strict und die Prüfoptionen
"strict": true schaltet eine Gruppe von Prüfungen auf einmal ein: noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, strictBuiltinIteratorReturn, noImplicitThis und useUnknownInCatchVariables. Das ist der Standard in TypeScript 7 und in jedem ausführbaren Beispiel hier aktiv. Code für den Strict Mode grenzt einen Wert ein, bevor er ihn verwendet, wenn der Wert fehlen könnte:
Ohne Annotation lässt sich der Typ eines Parameters nicht ableiten, und noImplicitAny meldet das:
index.ts(2,17): error TS7006: Parameter 'n' implicitly has an 'any' type.
strict enthält nicht jede nützliche Prüfung. Zwei, die sich lohnen, sind noUncheckedIndexedAccess (ein Array-Element oder ein Zugriff über eine Index-Signatur hat den Typ T | undefined) und exactOptionalPropertyTypes (eine optionale Eigenschaft darf nicht explizit auf undefined gesetzt werden); tsc --init schaltet beide ein. Stilprüfungen wie noUnusedLocals, noImplicitReturns und noFallthroughCasesInSwitch sind standardmäßig aus.
Welche Dateien: include, exclude, rootDir, outDir
Ohne include oder files enthält das Projekt jede Datei mit der Endung .ts, .tsx oder .d.ts im Ordner und seinen Unterordnern. node_modules bleibt immer außen vor. Das outDir bleibt ebenfalls außen vor, aber nur, solange du exclude nicht gesetzt hast: Eine eigene exclude-Liste ersetzt diesen Standard, also nimm den Ausgabeordner darin auf. include und exclude akzeptieren Glob-Muster:
{
"include": ["src", "scripts/**/*.ts"],
"exclude": ["src/**/*.test.ts"]
}
exclude filtert nur, was include gefunden hat. Eine Datei, die von einer eingeschlossenen Datei importiert wird, wird trotzdem kompiliert.
outDir ist das Ziel der Ausgabe, und rootDir ist der Teil des Quellbaums, der dorthin gespiegelt wird: Mit "rootDir": "./src" wird aus src/api/users.ts die Datei dist/api/users.js. Setze beides. rootDir ist standardmäßig der Ordner mit der tsconfig.json. Setzt du also nur outDir, während die Quellen in src liegen, bricht TypeScript 7 ab mit:
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.
Ausgabeoptionen: noEmit, declaration, sourceMap
"noEmit": truemachttsczu einem reinen Typprüfer. Nutze es, wenn ein anderes Tool (ein Bundler,tsx, das Type Stripping von Node.js) das JavaScript erzeugt."declaration": trueschreibt pro Modul eine.d.ts-Datei, also die Typen ohne den Code. Bibliotheken brauchen das, damit ihre Nutzer Typen bekommen.declarationMapergänzt Maps für "Gehe zu Definition" in die.ts-Quelle."sourceMap": trueschreibt.js.map-Dateien, damit Debugger und Stacktraces auf die.ts-Zeilen zeigen."noEmitOnError": trueschreibt nichts, solange es Typfehler gibt. Ohne diese Option meldettscdie Fehler und schreibt das JavaScript trotzdem.
types, esModuleInterop und skipLibCheck
types listet die @types-Pakete auf, die global geladen werden, ohne Import. Der Standardwert in TypeScript 7 ist eine leere Liste, also ergänzt du nach npm install --save-dev @types/node auch "types": ["node"]; sonst bleiben process und require unbekannt (error TS2591: Cannot find name 'process'). Test-Runner mit globalen Funktionen, etwa describe von Jest, kommen in dieselbe Liste.
esModuleInterop lässt Default-Imports von CommonJS-Paketen funktionieren (import express from "express"). In TypeScript 7 ist es immer aktiv, und es auf false zu setzen, ist ein Fehler.
skipLibCheck überspringt die Typprüfung von Deklarationsdateien. Das beschleunigt Builds und vermeidet Fehler in node_modules, die du nicht beheben kannst, auf Kosten davon, dass Konflikte zwischen den Typen zweier Bibliotheken unbemerkt bleiben. Die meisten Projekte schalten es ein.
Einstellungen mit extends teilen
extends lädt eine andere Konfiguration und lässt diese Datei Teile davon überschreiben:
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}
compilerOptions werden Option für Option zusammengeführt, während include, exclude und files aus der Basis ersetzt statt zusammengeführt werden, wenn diese Datei sie setzt. Pfade in der Basisdatei werden relativ zur Basisdatei aufgelöst. extends akzeptiert auch ein Paket: Das Projekt @tsconfig/bases veröffentlicht eines pro Umgebung, zum Beispiel npm install --save-dev @tsconfig/node24 und dann "extends": "@tsconfig/node24/tsconfig.json".
Um die endgültigen Einstellungen zu sehen, nachdem alle extends und Standardwerte angewendet wurden, führe aus:
npx tsc --showConfig
In TypeScript 7 entfernte Optionen
TypeScript 6 hat diese Einstellungen als veraltet markiert, und TypeScript 7 hat sie entfernt. Eine Konfiguration, die noch eine davon nutzt, scheitert mit error TS5108 oder TS5102, zum Beispiel Option 'baseUrl' has been removed. Please remove it from your configuration.
| Entfernte Einstellung | Stattdessen |
|---|---|
"target": "es5" | es2015 oder neuer |
"moduleResolution": "node" (node10) oder "classic" | nodenext oder bundler |
"module": "amd", "umd", "system", "none" | nodenext, esnext oder preserve, und für andere Formate ein Bundler |
baseUrl | paths-Einträge relativ zur tsconfig-Datei |
outFile | Ein Bundler |
downlevelIteration | Nichts: Ziele ab es2015 unterstützen Iteration nativ |
"esModuleInterop": false, "allowSyntheticDefaultImports": false, "alwaysStrict": false | Zeile entfernen; diese Optionen sind immer aktiv |
Die Seite zu TypeScript 7 listet die übrigen Änderungen dieser Version auf, auch die neuen Standardwerte, die diese Tabelle nicht abdeckt.
Häufig gestellte Fragen
Was ist tsconfig.json?
Die Konfigurationsdatei eines TypeScript-Projekts. Ihr Vorhandensein markiert den Ordner als Projektwurzel, compilerOptions legt fest, wie der Compiler Code prüft und ausgibt, und include, exclude oder files bestimmen, welche Dateien zum Projekt gehören. tsc ohne Argumente liest sie ein.
Wie erstelle ich eine tsconfig.json?
Führe im Projektordner (mit installiertem TypeScript) npx tsc --init aus. Das schreibt eine tsconfig.json mit empfohlenen Einstellungen und einem Kommentar zu jeder Option. Du kannst die Datei auch von Hand schreiben; {} ist eine gültige tsconfig, die überall die Standardwerte nutzt.
Auf welchen Wert sollte target in der tsconfig stehen?
Auf die älteste JavaScript-Version, auf der dein Code laufen muss. Für aktuelles Node.js ist es2022 oder neuer sicher; der Standardwert von TypeScript 7 ist es2025. target steuert, welche neuere Syntax für ältere Engines umgeschrieben wird, und wählt außerdem das Standard-lib, also die eingebauten APIs, die der Checker kennt.
Was ist der Unterschied zwischen module und moduleResolution?
module bestimmt, welche Art von Modulcode der Compiler schreibt (ES import/export oder CommonJS require) und welche Modulregeln gelten. moduleResolution bestimmt, wie ein Importpfad wie "./utils.js" oder "lodash" auf der Festplatte gefunden wird. Nimm nodenext für Code, den Node.js ausführt, und module: "preserve" (was die Auflösung bundler mit sich bringt) für Code, den ein Bundler verarbeitet.
Darf tsconfig.json Kommentare enthalten?
Ja. Der Compiler liest sie als JSON mit Kommentaren: Kommentare mit // und /* */ sowie abschließende Kommas sind erlaubt. Deshalb schreibt tsc --init eine Datei voller auskommentierter Optionen. Andere Tools, die sie als striktes JSON parsen, können daran scheitern.