TypeScript in Node: Das praktische Setup
Sie schreiben bereits TypeScript für den Browser. Jetzt benötigen Sie es serverseitig – für eine API, ein Build-Script oder SSR. Das Problem: Die meisten Setup-Anleitungen sind veraltet und empfehlen CommonJS-Konfigurationen oder Tools, die nicht mit modernem Node.js übereinstimmen.
Dieser Leitfaden behandelt zwei Ansätze für Ihr TypeScript-Node.js-Setup: Kompilierung mit tsc und Ausführung von JavaScript oder direkte Ausführung von .ts-Dateien mit Nodes nativer Type-Stripping-Funktion. Beide funktionieren. Jeder passt zu unterschiedlichen Szenarien.
Wichtigste Erkenntnisse
- Setzen Sie
"type": "module"in package.json, um ESM standardmäßig für moderne TypeScript-Node.js-Projekte zu aktivieren - Verwenden Sie
tsc-Kompilierung für Production-Deployments, veröffentlichte Packages und Code, der Enums, Namespaces oder Parameter Properties verwendet - Verwenden Sie Nodes natives Type-Stripping für lokale Scripts, Development-Server und schnelle Prototypen
- Verwenden Sie immer
import typefür reine Type-Imports, um Laufzeitfehler beim Type-Stripping zu vermeiden - Führen Sie
tsc --noEmitin der CI aus, da Nodes Type-Stripping keine Typprüfung durchführt
Die Grundlage: Node 24 LTS und ESM
Beginnen Sie mit dieser Basis:
{
"type": "module"
}
Dies aktiviert ESM standardmäßig. Ihre Imports verwenden ESM-Syntax, und Node löst Module entsprechend auf.
Node 24 ist die aktuelle LTS-Baseline für dieses Setup (kann hier heruntergeladen werden: https://nodejs.org/en/download).
Ansatz 1: Mit tsc kompilieren, JavaScript ausführen
Dieser Ansatz trennt Kompilierung von Ausführung. Verwenden Sie ihn für Production-Deployments, veröffentlichte Packages oder wenn Sie vollständige TypeScript-Feature-Unterstützung benötigen.
tsconfig für Node 24
{
"compilerOptions": {
"target": "ES2024",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"rootDir": "src",
"outDir": "dist",
"strict": true,
"skipLibCheck": true,
"declaration": true,
"sourceMap": true,
"verbatimModuleSyntax": true,
"isolatedModules": true,
"lib": ["ES2024"]
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
Wichtige Einstellungen in dieser Konfiguration:
module: NodeNextundmoduleResolution: NodeNext: Entspricht dem tatsächlichen Modul-Auflösungsverhalten von NodeverbatimModuleSyntax: Erfordert explizitesimport typefür reine Type-Imports – entscheidend zur Vermeidung von Laufzeitfehlern (siehe TypeScript-Dokumentation: https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax)isolatedModules: Gewährleistet Kompatibilität mit Single-File-Transpilation-Tools
Scripts
{
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsc --watch"
}
}
Führen Sie npm run build aus, dann npm start. Das kompilierte JavaScript befindet sich in dist/.
Ansatz 2: Nodes natives TypeScript (Type-Stripping)
Node hat native TypeScript-Unterstützung in Node 22 eingeführt und in Node 24 LTS über Type-Stripping stabilisiert. Verwenden Sie es für Scripts, lokales Tooling oder Development, wenn Sie keine Build-Schritte wünschen.
Offizielle Dokumentation: https://nodejs.org/api/typescript.html
Wie es funktioniert
In Node 24+ führen Sie direkt aus:
node src/index.ts
(Ältere Node-Versionen erforderten experimentelle Flags; Node 24 nicht.)
Kritische Einschränkungen
Nodes natives TypeScript entfernt nur Typen – es führt keine Typprüfung durch. Sie benötigen weiterhin tsc --noEmit in der CI oder Ihrem Editor, um Fehler zu erkennen.
Weitere Einschränkungen:
- Ignoriert tsconfig.json: Node liest Ihre Compiler-Optionen nicht
- Erfordert explizite Dateierweiterungen: Schreiben Sie
import { foo } from './utils.js', auch wenn die Quelldateiutils.tsist - Respektiert ESM- vs. CJS-Regeln: Ihr
package.json-type-Feld ist wichtig - Führt kein TypeScript aus node_modules aus: Dependencies müssen kompiliertes JavaScript sein
- Unterstützt nur löschbare Syntax: Enums, Namespaces und Parameter Properties schlagen fehl, es sei denn, Sie aktivieren
--experimental-transform-types
Dateierweiterungen sind wichtig
Für gemischte Modulformate:
.mts-Dateien → immer ESM.cts-Dateien → immer CommonJS.ts-Dateien → folgen dempackage.json-type-Feld
Discover how at OpenReplay.com.
Laufzeitfehler vermeiden
Verwenden Sie import type für reine Type-Imports:
// Korrekt
import type { Request, Response } from 'express'
import express from 'express'
// Falsch - schlägt zur Laufzeit mit Type-Stripping fehl
import { Request, Response } from 'express'
Aktivieren Sie verbatimModuleSyntax in Ihrer tsconfig, um diese während der Entwicklung zu erkennen, auch wenn Node die Konfiguration zur Laufzeit ignoriert.
Welchen Ansatz verwenden
Verwenden Sie tsc-Kompilierung für:
- Production-Deployments
- Veröffentlichte npm-Packages
- Code, der Enums, Namespaces oder Parameter Properties verwendet
- Projekte, die Source Maps in Production benötigen
Verwenden Sie natives Type-Stripping für:
- Lokale Scripts und Tooling
- Development-Server (kombiniert mit
--watch) - Schnelle Prototypen
- SSR-Development-Builds
Ein praktisches Development-Setup
Kombinieren Sie beide Ansätze:
{
"scripts": {
"dev": "node --watch src/index.ts",
"typecheck": "tsc --noEmit",
"build": "tsc",
"start": "node dist/index.js"
}
}
Development verwendet native Ausführung für Geschwindigkeit. CI führt typecheck aus. Production deployt kompiliertes JavaScript.
Fazit
Das moderne TypeScript-Node.js-Setup ist einfacher, als ältere Anleitungen suggerieren. Verwenden Sie ESM, konfigurieren Sie NodeNext-Modulauflösung und wählen Sie Ihre Ausführungsstrategie basierend auf dem Kontext. Natives Type-Stripping funktioniert für Development und Scripts. Kompilierte Ausgabe funktioniert für Production und Packages. Beide Ansätze teilen denselben Quellcode und dieselbe tsconfig – Sie sind nicht an einen der beiden gebunden.
FAQs
Die Modulauflösung von Node erfordert explizite Dateierweiterungen für ESM. Wenn Sie import from ./utils.js schreiben, sucht Node zur Laufzeit nach genau diesem Pfad, auch wenn Ihre Quelldatei utils.ts ist. Da Type-Stripping Typen entfernt, aber Dateien nicht umbenennt, und tsc .js-Dateien ausgibt, stellt die Verwendung von .js-Erweiterungen in Ihrem Quellcode sicher, dass Imports in beiden Szenarien funktionieren.
Nicht standardmäßig. Enums erfordern Code-Transformation, nicht nur Typ-Entfernung. Sie können das Flag --experimental-transform-types aktivieren, um Enums, Namespaces und Parameter Properties zu unterstützen, aber dies erhöht die Komplexität. Für einfachere Setups sollten Sie const-Objekte mit as const-Assertions als Alternative zu Enums in Betracht ziehen.
Für die meisten Anwendungsfälle nein. Nodes natives Type-Stripping in Node 24 übernimmt die direkte .ts-Ausführung. Tools wie ts-node und tsx sind optionale Komfortfunktionen, die tsconfig.json-Unterstützung, Path-Alias-Auflösung und vollständige TypeScript-Transformationen ohne Flags hinzufügen. Verwenden Sie sie nur, wenn Ihr Setup diese Features benötigt.
Bei Verwendung von nativem Type-Stripping führt Node Ihre .ts-Dateien direkt aus, sodass Zeilennummern in Stack Traces mit Ihrer Quelle übereinstimmen. Für kompilierten Code aktivieren Sie sourceMap in tsconfig.json, und Node verwendet automatisch .js.map-Dateien, um ursprüngliche TypeScript-Positionen in Fehlern und Debugger-Sitzungen anzuzeigen.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.