TypeScript Configuration: A Journey Through Project Maturity
Every TypeScript project starts with good intentions and a `tsconfig.json` file. But as projects mature, so too must their TypeScript configuration. Here's the journey I've observed across multiple projects.
Stage 1: The Permissive Beginning
Most projects start with a relaxed configuration:
{
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
"strict": false,
"noImplicitAny": false
}
}
This works great for getting started quickly, especially when migrating from JavaScript. But it doesn't provide the full benefits of TypeScript's type system.
Stage 2: Tightening the Screws
As the codebase grows and bugs start appearing, teams typically enable more strict checking:
{
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
}
}
Stage 3: Production-Ready Configuration
Mature projects often end up with comprehensive configurations:
{
"compilerOptions": {
"target": "ES2020",
"module": "esnext",
"moduleResolution": "bundler",
"strict": true,
"exactOptionalPropertyTypes": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true
}
}
The Path Dependency Problem
The challenge is that it's much easier to start strict than to migrate to strict later. Once you have thousands of lines of loosely-typed code, the migration becomes daunting.
My Recommended Starting Point
For new projects, I recommend starting with a moderately strict configuration:
{
"compilerOptions": {
"target": "ES2022",
"module": "esnext",
"moduleResolution": "bundler",
"strict": true,
"noUnusedLocals": true,
"noImplicitReturns": true,
"allowUnusedLabels": false,
"allowUnreachableCode": false
}
}
Incremental Migration Strategy
For existing projects, enable strict checking incrementally:
- Start with `noImplicitAny: true`
- Add `strictNullChecks: true`
- Enable other strict flags one by one
- Use `// @ts-expect-error` comments for temporary exceptions
The key is consistency and gradual improvement. TypeScript's configuration should evolve with your project's maturity, not fight against it.