Option reference — what each compiler option actually does
The table below is the fast-lookup version of the checkboxes above, plus the values you'll most often want. It covers the options that account for nearly every real-world tsconfig.
| Option | Plain-English effect | Typical value |
|---|---|---|
| target | Newest JavaScript syntax the output may contain. Also sets the default lib. | ES2022+ |
| module | Module system of the output: require() (commonjs) or import (esnext), or Node's own dual rules (nodenext). | nodenext / esnext |
| moduleResolution | Algorithm used to find what an import path refers to. Must match who actually loads the code: Node → nodenext, a bundler → bundler. | nodenext / bundler |
| strict | Umbrella that enables the nine strict-family checks. The single highest-value line in the file. | true |
| strictNullChecks | Makes "possibly undefined" a compile error instead of a production crash. | true (via strict) |
| noImplicitAny | Forbids silent any when inference fails — the flag that makes TypeScript actually typed. | true (via strict) |
| noUncheckedIndexedAccess | Array/record lookups include undefined. Stricter than strict; catches real off-by-one bugs. | true if you can |
| esModuleInterop | Fixes default imports from CommonJS packages. Also enables allowSyntheticDefaultImports. | true |
| skipLibCheck | Skips checking dependency .d.ts files. Large compile-time win; hides conflicts between dependencies' types. | true |
| isolatedModules | Guarantees each file can be transpiled alone — required for esbuild, swc, and Vite, which work file-by-file. | true with bundlers |
| verbatimModuleSyntax | Imports/exports are emitted exactly as written; type-only imports must be marked import type. Replaces the older importsNotUsedAsValues. | true for libraries |
| resolveJsonModule | Allows importing .json files, typed from their contents. See the section below. | true |
| jsx | What happens to JSX: compiled with the modern runtime (react-jsx), left alone for a bundler (preserve), or classic React.createElement (react). | react-jsx |
| declaration | Emit .d.ts files so consumers of your package get types. | true for libraries |
| declarationMap | Source maps for .d.ts — "Go to definition" lands in your .ts, not the declaration. | true with declaration |
| sourceMap | Emit .js.map so runtime stack traces map back to TypeScript lines. | true |
| outDir / rootDir | Where output goes / what the source root is. rootDir's folder structure is mirrored into outDir. | dist / src |
| baseUrl + paths | Import aliases like @/utils. Checked by tsc only — the bundler or a runtime loader must resolve them too. | as needed |
| noEmit | Type-check without producing files — the standard setup when a bundler emits the JS. | true with bundlers |
| composite / incremental | Project-reference builds and build-info caching for monorepos and faster re-compiles. | monorepos |
| lib | Which built-in type definitions exist: DOM globals, ES library features. Pure Node code should drop DOM. | ["ES2022"] or +DOM |
| allowJs / checkJs | Include .js files in compilation / also type-check them. The gradual-migration switches. | migration only |
| forceConsistentCasingInFileNames | Catches import "./Utils" vs utils.ts — works on macOS, breaks on Linux CI. | true |
Common errors this file causes — and which option fixes them
When TypeScript errors mention modules, JSX, or JSON, the bug is usually in tsconfig, not your code:
- "Cannot use JSX unless the '--jsx' flag is provided" — the
jsxoption is unset. Pickreact-jsxfor modern React (no per-file React import needed) orpreserveif your bundler compiles JSX itself. - "Cannot find module './data.json'" — enable
resolveJsonModule. See the dedicated section below. - "Module can only be default-imported using the 'esModuleInterop' flag" — exactly what it says: turn on
esModuleInterop. Without it, CommonJS packages needimport * as x from "x". - "Relative import paths need explicit file extensions in ECMAScript imports" — you're on
moduleResolution: nodenextwith ESM, where Node itself requires./util.jsextensions (yes,.js— the compiled name — even in .ts source). Either add extensions or, if a bundler loads your code, switch tomoduleResolution: bundler, which doesn't require them. - "Object is possibly 'undefined'" — not a config bug:
strictNullChecksdoing its job. Handle the undefined case, or use optional chaining. Turning the flag off trades this compile error for runtime crashes. - "Cannot redeclare block-scoped variable" across unrelated files — files without imports/exports are treated as global scripts sharing one scope. Add an
export {}to the file so it becomes a module. - Option combinations that fight:
module: commonjswithmoduleResolution: bundleris invalid;module: nodenextrequiresmoduleResolution: nodenext. The generator keeps these pairs consistent when you change either one. - Alias imports compile but crash at runtime —
pathsonly teaches the type checker where@/utilslives. Node and browsers don't read tsconfig; your bundler (or a loader) must be configured with the same aliases.
resolveJsonModule — importing JSON with types
With resolveJsonModule on, this works and the import is typed from the file's actual contents:
import config from "./config.json";
// config.port is number, config.name is string — inferred from the JSON
console.log(config.port);Details worth knowing: the inferred type is wide ("production" in the file types as string, not the literal); the JSON becomes a real module in the output, so it's compiled into your build rather than read at runtime — editing the .json after compiling changes nothing until you rebuild; and under module: nodenext ESM, Node additionally requires an import attribute (import config from "./config.json" with { type: "json" }). If you want runtime-loaded, validated config, read the file with fs and validate it — resolveJsonModule is for build-time data like locale strings, fixtures, and version manifests.