Skip to content
TypeScript ts config 4 min read

Other Useful Compiler Options

Beyond target, module, and the strict family, a handful of compilerOptions show up in almost every well-configured project. They tune which APIs the type checker knows about, how interop with CommonJS works, how fast compilation runs, and what extra artifacts are emitted. None are strictly required, but knowing them lets you build a tsconfig.json that is fast, safe, and friendly to your tooling. This page tours the most valuable ones: lib, esModuleInterop, skipLibCheck, sourceMap, declaration, isolatedModules, and noUncheckedIndexedAccess.

lib

lib chooses which built-in type declarations are available — the DOM, specific ECMAScript versions, web workers, and so on. If omitted, it defaults based on target, but you set it explicitly to add or remove environments.

{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"]
  }
}

A Node-only project should drop "DOM" so browser globals like document are not typed as available. A browser project keeps "DOM" and "DOM.Iterable". Remember lib only affects types — it never adds polyfills.

esModuleInterop

esModuleInterop fixes the rough edges of importing CommonJS modules from ESM-style code. It enables clean default imports of CJS packages and emits helper shims so the interop matches Babel’s behavior.

// With esModuleInterop: true
import express from "express";

// Without it you would be forced into:
import * as express from "express"; // and express() may not be callable

Turning it on also implicitly enables allowSyntheticDefaultImports for the type checker. It is on by default in configs scaffolded by modern tools and recommended for nearly all projects.

skipLibCheck

skipLibCheck tells the compiler to skip type-checking the contents of .d.ts declaration files (including those in node_modules). It does not skip your code — only the library declarations.

{
  "compilerOptions": {
    "skipLibCheck": true
  }
}

This noticeably speeds up builds and sidesteps errors caused by conflicting or buggy third-party type definitions you cannot fix. The tradeoff is that genuine type mismatches inside dependencies go unreported, but in practice the speed and stability win out.

sourceMap & declaration

These two control emitted artifacts. sourceMap produces .js.map files so debuggers and stack traces map back to your .ts source. declaration emits .d.ts files so consumers of a library get full type information.

{
  "compilerOptions": {
    "sourceMap": true,
    "declaration": true,
    "declarationMap": true
  }
}

Enable sourceMap for any app you need to debug, and declaration for any package you publish. declarationMap lets editors “go to definition” jump into your original source instead of the generated .d.ts.

isolatedModules

isolatedModules enforces that each file can be transpiled on its own, without whole-program type information. This is required by single-file transpilers like esbuild, swc, and Babel, which compile files independently.

// ❌ Error under isolatedModules: a type re-export must use `export type`
export { SomeType } from "./types";

// ✅ Correct
export type { SomeType } from "./types";

The flag does not change output; it just rejects patterns (certain const enum uses, ambiguous re-exports) that those fast transpilers cannot handle correctly. Turn it on if your build uses esbuild/swc/Vite.

noUncheckedIndexedAccess

This flag adds undefined to the type of any value read through an index signature or array index, reflecting the runtime reality that the element might not exist. It is not part of strict, so enable it separately.

const scores: Record<string, number> = { math: 90 };

// With noUncheckedIndexedAccess: scores["x"] is number | undefined
const s = scores["science"];
// ❌ Error: 's' is possibly 'undefined'.
console.log(s.toFixed(1));

It surfaces a large class of real bugs (missing keys, out-of-bounds reads) but adds friction, so introduce it deliberately. The table summarizes everything covered.

OptionPurposeTypical value
libWhich built-in type libs are available["ES2022", "DOM"]
esModuleInteropClean CJS default importstrue
skipLibCheckSkip checking .d.ts filestrue
sourceMapEmit debug source mapstrue (apps)
declarationEmit .d.ts for consumerstrue (libraries)
isolatedModulesSafe single-file transpilationtrue (esbuild/swc)
noUncheckedIndexedAccessAdd undefined to indexed readstrue (opt-in)

Best Practices

  • Set lib explicitly and drop "DOM" from Node-only projects.
  • Keep esModuleInterop: true for painless CommonJS interop.
  • Enable skipLibCheck: true for faster builds and to dodge broken third-party types.
  • Turn on sourceMap for apps you debug and declaration for packages you publish.
  • Use isolatedModules: true whenever a single-file transpiler (esbuild/swc/Vite) builds your code.
  • Adopt noUncheckedIndexedAccess to catch missing-key and out-of-bounds bugs.
  • Add declarationMap alongside declaration so editors jump to your real source.
Last updated June 29, 2026
Was this helpful?