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.
| Option | Purpose | Typical value |
|---|---|---|
lib | Which built-in type libs are available | ["ES2022", "DOM"] |
esModuleInterop | Clean CJS default imports | true |
skipLibCheck | Skip checking .d.ts files | true |
sourceMap | Emit debug source maps | true (apps) |
declaration | Emit .d.ts for consumers | true (libraries) |
isolatedModules | Safe single-file transpilation | true (esbuild/swc) |
noUncheckedIndexedAccess | Add undefined to indexed reads | true (opt-in) |
Best Practices
- Set
libexplicitly and drop"DOM"from Node-only projects. - Keep
esModuleInterop: truefor painless CommonJS interop. - Enable
skipLibCheck: truefor faster builds and to dodge broken third-party types. - Turn on
sourceMapfor apps you debug anddeclarationfor packages you publish. - Use
isolatedModules: truewhenever a single-file transpiler (esbuild/swc/Vite) builds your code. - Adopt
noUncheckedIndexedAccessto catch missing-key and out-of-bounds bugs. - Add
declarationMapalongsidedeclarationso editors jump to your real source.