// strict: true enables ALL of these at once:// - strictNullChecks: null/undefined not assignable to other types// - strictFunctionTypes: contravariant function parameter checking// - strictBindCallApply: type-check bind, call, apply// - strictPropertyInitialization: class props must be initialized// - noImplicitAny: error on implicit any// - noImplicitThis: error on 'this' with implicit any type// - useUnknownInCatchVariables: catch variable is unknown, not any// - alwaysStrict: emit "use strict" in every file
output
// strict: true is the recommended baseline for all new projects
Note Always start new projects with strict: true. You can selectively disable individual checks if needed (e.g., "strictPropertyInitialization": false) while keeping the rest. Enabling strict on a large existing JS-to-TS migration can produce thousands of errors — enable checks incrementally in that case.
strict modetsconfig strictstrictNullChecksenable all checksrecommended config
// target: which JS version to emit// "ES5" — maximum compat (IE11), heavy downleveling// "ES2020" — good baseline for modern browsers// "ES2022" — class fields, top-level await, cause in Error// "ESNext" — latest; may change between TS versions// module: which module system to use// "commonjs" — Node.js require/exports// "es2022" — ES modules with top-level await// "esnext" — latest ES module features// "node16" / "nodenext" — Node.js ESM with .mjs/.cjs awareness// "preserve" — keep import/export as written (TS 5.4+)
output
// target controls syntax downleveling; module controls import/export format
Note For bundled apps (Vite, webpack), set target to your browser baseline and module to ESNext — the bundler handles the rest. For Node.js, use module: "node16" or "nodenext" which correctly resolves .mjs/.cjs and package.json "type" fields. The new "preserve" module option (TS 5.4+) emits imports exactly as written.
targetmoduleES versionmodule systemcommonjs vs esmtsconfig target
// Path aliases shorten deep relative imports like ../../../../utils
Note paths only affects TypeScript's type resolution — it does NOT rewrite imports in emitted JS. Your bundler (Vite, webpack) or runtime (ts-node, tsx) needs matching alias config. For Node.js, package.json "imports" with subpath patterns is the modern alternative that works without bundler config.
// noEmit: true — only type-check, don't produce .js files// Used when a bundler (Vite, esbuild, SWC) handles transpilation
{
"compilerOptions": {
"noEmit": true// tsc is just the type checker
}
}
// declaration: true — generate .d.ts files alongside .js// Used for libraries that need to ship type definitions
{
"compilerOptions": {
"declaration": true,
"declarationDir": "./dist/types",
"emitDeclarationOnly": true// only .d.ts, no .js
}
}
output
// noEmit for apps (bundler compiles); declaration for libraries (ship types)
Note Most modern app setups use noEmit: true because tools like Vite, esbuild, and SWC transpile much faster than tsc. Library authors use declaration: true (often with emitDeclarationOnly) to generate .d.ts files while letting another tool handle .js output.
// isolatedModules: true// Ensures each file can be transpiled independently// Required for: Babel, esbuild, SWC, Vite// Disallows: const enums across files, namespace merging across files// verbatimModuleSyntax: true (TS 5.0+, replaces isolatedModules)// Forces you to use 'import type' for type-only importsimporttype { User } from"./models"; // erased at runtimeimport { processUser } from"./handlers"; // kept at runtime// import { User } from "./models";// Error with verbatimModuleSyntax: 'User' is a type and must use 'import type'
output
// Enforces clean separation of type imports from value imports
Note verbatimModuleSyntax (TS 5.0+) supersedes both isolatedModules and the older importsNotUsedAsValues. It makes the distinction between type and value imports explicit and mandatory. This produces cleaner output and avoids side-effect confusion. Recommended for all new projects.
// tsc --build only recompiles packages that changed
Note Project references enable incremental builds in monorepos. Each sub-project needs "composite": true. Build with tsc --build (or tsc -b) which understands dependency order. This dramatically speeds up type-checking in large codebases by skipping unchanged packages.
// A solid starting tsconfig for a modern bundled web app
Note moduleResolution: "bundler" (TS 5.0+) matches how Vite/webpack/esbuild resolve modules — it supports exports maps, .ts extensions in imports, and does not require file extensions. skipLibCheck: true speeds up compilation by not checking node_modules .d.ts files (only your code is checked).