tsconfig Strictness
Configure compiler strictness flags for maximum safety without blocking pragmatic migration paths.
The strict Flag and Its Family
`strict: true` enables `strictNullChecks`, `strictFunctionTypes`, `strictBindCallApply`, `strictPropertyInitialization`, `noImplicitAny`, `noImplicitThis`, and `alwaysStrict`. New projects should start with strict enabled from day one.
Migrating legacy JavaScript enables strict flags incrementally — turn on one flag per PR, fix violations, and prevent regression with CI. `strictNullChecks` alone catches the most production bugs.
- `strict: true` enables the full suite
- Enable flags incrementally in migrations
- strictNullChecks has highest bug-finding ROI
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true
}
}High-Value Additional Flags
`noUncheckedIndexedAccess` adds `undefined` to indexed access — arrays and records require explicit checks. `exactOptionalPropertyTypes` distinguishes missing vs explicitly undefined optional props. `noImplicitReturns` ensures all code paths return in functions with return types.
`verbatimModuleSyntax` enforces explicit `import type` and prevents accidental value imports of types. Enable when tooling supports it for cleaner output and fewer circular import bugs.
- noUncheckedIndexedAccess for array safety
- exactOptionalPropertyTypes for precise optionals
- verbatimModuleSyntax for clean imports
Module and Interop Settings
`esModuleInterop` and `allowSyntheticDefaultImports` simplify default imports from CommonJS modules. `isolatedModules` ensures each file transpiles independently — required for Babel and esbuild and catches re-export issues.
`skipLibCheck` skips typechecking of declaration files — faster builds with slightly less safety. Most projects enable it; fix upstream @types issues locally with module augmentation when needed.
- isolatedModules for Babel/esbuild
- esModuleInterop for CJS default imports
- skipLibCheck for build speed
Project References and Monorepos
Split monorepos with `composite: true` and project references for incremental builds. Each package has its own tsconfig extending a base config with shared strict flags.
Path mapping at the root coordinates packages: `"references": [{ "path": "./packages/ui" }]`. `tsc --build` compiles the dependency graph in order, caching outputs.
- Project references for monorepos
- Shared base tsconfig for consistency
- Incremental builds with composite
Balancing Strictness and Velocity
Stricter configs slow initial migration but accelerate long-term development. Document any intentional `@ts-expect-error` with ticket links and expiration plans — suppressions without context become permanent holes.
Use ESLint TypeScript rules (`@typescript-eslint`) alongside compiler flags for patterns the compiler cannot enforce — consistent type imports, explicit return types on exports, and ban on non-null assertions in critical paths.
- Document ts-expect-error with tickets
- ESLint complements compiler flags
- Stricter configs pay off over time