TypeScript tsconfig Patterns Reference
TypeScript tsconfig patterns reference
TL;DR
- Bottom line: Start every project with
strict: true,moduleResolution: "bundler"(or"nodenext"),target: "es2022", andskipLibCheck: true. - Key tool/command:
tsc --showConfig - Watch out for: Setting
pathsaliases without configuring the same aliases in your bundler — TypeScript does NOT rewrite import paths. - Works with: TypeScript 5.0–5.7, Node.js 18+, all major bundlers.
Constraints
strict: trueis non-negotiable for new projectsmoduleResolutionmust match yourmodulesetting —"bundler"for Vite/webpack,"nodenext"for pure Node.js- Never set
skipLibCheck: falsein large projects — dramatically slows compilation targetandlibare separate concerns — target controls emit, lib controls typespathsaliases require bundler config too — TypeScript does NOT rewrite import paths
Quick Reference
| Option | Recommended | Purpose |
|---|---|---|
strict | true | All strict type checks |
target | "es2022" | Emit syntax level |
module | "esnext" / "nodenext" | Module system |
moduleResolution | "bundler" / "nodenext" | How TS finds modules |
skipLibCheck | true | Skip .d.ts checking |
isolatedModules | true | Required by esbuild/swc/Vite |
verbatimModuleSyntax | true | Explicit type-only imports |
noUncheckedIndexedAccess | true | Index returns T | undefined |
resolveJsonModule | true | Import .json files |
declaration | true (libs) | Generate .d.ts files |
incremental | true | Faster rebuilds |
noEmit | true (bundler) | Bundler handles emit |
Decision Tree
START
├── Pure Node.js (no bundler)?
│ ├── YES → module: "nodenext", moduleResolution: "nodenext"
│ └── NO ↓
├── Using Vite, webpack, esbuild?
│ ├── YES → module: "esnext", moduleResolution: "bundler", noEmit: true
│ └── NO ↓
├── Building npm library?
│ ├── YES → declaration: true, declarationMap: true, outDir: "./dist"
│ └── NO ↓
├── React project?
│ ├── YES → jsx: "react-jsx"
│ └── NO ↓
├── Monorepo?
│ ├── YES → composite: true, references: [...]
│ └── NO ↓
└── DEFAULT → strict: true, target: "es2022", skipLibCheck: true
Step-by-Step Guide
1. Initialize tsconfig.json
Generate a starter config. [src5]
npx tsc --init
Verify: ls tsconfig.json → file exists
2. Set base options
Essential options for every project. [src2]
{
"compilerOptions": {
"strict": true,
"target": "es2022",
"skipLibCheck": true,
"esModuleInterop": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"noUncheckedIndexedAccess": true,
"resolveJsonModule": true,
"forceConsistentCasingInFileNames": true,
"moduleDetection": "force"
}
}
3. Configure module resolution
Choose based on bundler vs Node.js. [src4]
// For bundlers (Vite, webpack):
{ "module": "esnext", "moduleResolution": "bundler", "noEmit": true }
// For pure Node.js:
{ "module": "nodenext", "moduleResolution": "nodenext", "outDir": "./dist" }
Code Examples
Vite + React + TypeScript
{
"compilerOptions": {
"strict": true, "target": "es2022",
"lib": ["es2022", "dom", "dom.iterable"],
"module": "esnext", "moduleResolution": "bundler",
"isolatedModules": true, "noEmit": true,
"jsx": "react-jsx",
"skipLibCheck": true, "noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true,
"baseUrl": ".", "paths": { "@/*": ["./src/*"] }
},
"include": ["src", "vite-env.d.ts"]
}
Node.js + Express Backend
{
"compilerOptions": {
"strict": true, "target": "es2022", "lib": ["es2022"],
"module": "nodenext", "moduleResolution": "nodenext",
"outDir": "./dist", "rootDir": "./src",
"sourceMap": true, "declaration": true, "incremental": true,
"skipLibCheck": true, "noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
npm Library
{
"compilerOptions": {
"strict": true, "target": "es2022", "lib": ["es2022"],
"module": "esnext", "moduleResolution": "bundler",
"outDir": "./dist", "rootDir": "./src",
"declaration": true, "declarationMap": true, "sourceMap": true,
"skipLibCheck": true, "noUncheckedIndexedAccess": true,
"isolatedModules": true, "verbatimModuleSyntax": true
},
"include": ["src/**/*"],
"exclude": ["**/*.test.ts"]
}
Anti-Patterns
Wrong: Skipping strict mode
// ❌ BAD — silent any, null bugs everywhere
{ "compilerOptions": { "strict": false, "target": "es5" } }
Correct: Always enable strict
// ✅ GOOD — catches bugs at compile time
{ "compilerOptions": { "strict": true, "target": "es2022" } }
Wrong: Using "moduleResolution": "node" with a bundler
// ❌ BAD — "node" is legacy, misses package.json exports
{ "module": "esnext", "moduleResolution": "node" }
Correct: Use "bundler" with bundlers
// ✅ GOOD — supports exports, no extension requirement
{ "module": "esnext", "moduleResolution": "bundler" }
Common Pitfalls
- verbatimModuleSyntax breaks CJS: Fix: only use with ESM output or
module: "nodenext". [src3] - paths aliases not working at runtime: Fix: add
vite-tsconfig-pathsortsconfig-paths. [src1] - Stale tsbuildinfo: Fix:
rm tsconfig.tsbuildinfo && npx tsc. [src6] - Missing DOM types on server: Fix:
"lib": ["es2022"]for Node.js. [src1] - exactOptionalPropertyTypes too strict: Fix: start with
strict: truealone. [src2] - outDir/rootDir mismatch: Fix: rootDir = common ancestor of source files. [src5]
Diagnostic Commands
# Show fully resolved tsconfig
npx tsc --showConfig
# Type-check without emitting
npx tsc --noEmit
# List files that would be compiled
npx tsc --listFiles
# Check TypeScript version
npx tsc --version
# Build with verbose diagnostics
npx tsc --extendedDiagnostics
Version History & Compatibility
| Version | Status | Key Additions | Notes |
|---|---|---|---|
| TS 5.7 | Current | — | Fully supports all listed options |
| TS 5.5 | Stable | isolatedDeclarations, extends arrays | — |
| TS 5.4 | Stable | verbatimModuleSyntax finalized | Replaces importsNotUsedAsValues |
| TS 5.0 | LTS | moduleResolution: "bundler" | First with bundler resolution |
| TS 4.x | EOL | — | Upgrade to 5.x |
When to Use / When Not to Use
| Use When | Don't Use When | Use Instead |
|---|---|---|
| Any TypeScript project | Using Deno | deno.json compilerOptions |
| Need precise type checking | Quick prototype | Plain JS |
| Building npm libraries | Using Bun exclusively | bunfig.toml |
Important Caveats
moduleResolution: "bundler"requiresmodule: "esnext"or"preserve"verbatimModuleSyntaxreplaces olderimportsNotUsedAsValues- TypeScript path aliases do NOT affect emitted JavaScript
composite: truerequiresdeclaration: trueand disallowsnoEmit: true