TypeScript Strict: Why I Never Turn It Off
The strict flag in tsconfig.json gets challenged on almost every project. Here's why I never give in, and what it concretely changes.
On almost every project, the same conversation comes up. Someone opens tsconfig.json and asks: "Can we set strict to false? It would simplify the types." The answer is no. Here's why.
What "strict" Actually Enables
The strict flag isn't a single setting — it's a shorthand that activates seven options at once. The two that change day-to-day work the most:
- noImplicitAny: forbids implicitly any-typed variables. Every variable without an inferable explicit type is an error.
- strictNullChecks: null and undefined are not assignable to type T. Every null case must be handled explicitly.
- strictFunctionTypes: variance checking on function parameter types.
- strictPropertyInitialization: class properties must be initialized in the constructor.
- noImplicitThis: this must be explicitly typed in functions.
The last five are fine-grained noise. The first two — noImplicitAny and strictNullChecks — are the ones that actually matter in production.
The Standard Objections
"It takes longer to write the types." Yes, at first. That time comes back at the first significant refactor, when the compiler finds the 12 broken callsites before the tests — or the users — do.
"We can enable it later." You can't, really. Adding strict to an existing project means fixing hundreds of errors on code nobody fully understands anymore. It's always harder than expected and often abandoned halfway. The debt is there — it's just invisible.
A Concrete Example
Here's the kind of bug strictNullChecks catches at compile time:
// Without strictNullChecks — compiles, crashes at runtime
function getUser(id: string): User {
return users.find(u => u.id === id);
// Inferred type: User | undefined
// TypeScript says nothing — but it's wrong
}
const user = getUser('abc');
console.log(user.name); // TypeError if the id doesn't existWith strictNullChecks, the `User` return type is a compile error: `Type 'User | undefined' is not assignable to type 'User'`. You're forced to handle the missing case at write time.
// With strictNullChecks — the contract is honest
function getUser(id: string): User | undefined {
return users.find(u => u.id === id);
}
const user = getUser('abc');
if (!user) throw new Error(`User ${id} not found`);
console.log(user.name); // TypeScript knows user is User hereThe Real Question
The cost of strict is front-loaded — you pay it at the start of a project, when types are new and code is still malleable. The benefit is long-term: fewer TypeErrors in production, safer refactors, faster onboarding for developers joining the codebase.
Disabling strict means taking on technical debt at the first file. It's not a style question — it's a question of deferred cost. I'd rather pay it upfront.
A codebase without strictNullChecks is a codebase that lies to its own compiler.
Written by
Casian Ciorba
Six years shipping production code — software, SaaS, mobile apps and AI integrations. I write about what I actually use on projects, not what makes conference talks.