Why Enabling TypeScript’s strictNullChecks is Worth the Refactor
Enable TypeScript’s strictNullChecks to catch null dereferences at compile time. Learn how it changes type inference, see a concrete React component refactor, and weigh trade‑offs for large codebases.
03 Jul 2026, 13:47 UTC

The Concrete Problem: Null‑Related Runtime Crashes
In many JavaScript codebases you’ll see a handful of failures that surface only when a value turns out to be null or undefined. A common pattern looks like this:
function getUserName(user) {
return user.name;
}
If user is ever null or undefined, the application throws and the stack trace points to user.name. Catching this bug is a matter of guessing, testing, or adding defensive code everywhere.
What strictNullChecks Changes
TypeScript’s strictNullChecks compiler flag turns the implicit allowance of null and undefined into an explicit part of the type system. When the flag is on, a variable declared as string can no longer be assigned null or undefined without a union type.
Key effects:
- Values that could be
nullorundefinedare represented asT | null | undefined. - Accessing a property on a potentially null value requires a check or a null‑safety operator.
- IDE autocompletion excludes null from the list of possible values, reducing accidental dereferences.
- Compile‑time errors surface for unsafe accesses that would otherwise crash at runtime.
Worked Example: Refactoring a Component
Consider a React component that receives a profile prop. With strictNullChecks disabled, the component might look like this:
interface Profile {
avatarUrl: string;
bio: string;
}
interface Props {
profile?: Profile;
}
const ProfileCard: React.FC = ({ profile }) => {
return (
<div>
<img src={profile.avatarUrl} alt="avatar" />
<p>{profile.bio}</p>
</div>
);
};
When profile is undefined, the component throws. Enabling strictNullChecks turns this into a compile‑time error:
// tsconfig.json
{
"compilerOptions": {
"strictNullChecks": true
}
}
Recompiling produces:
Property 'avatarUrl' does not exist on type 'Profile | undefined'.
Fixing the error is straightforward: guard against null or use nullish operators.
Approach 1 – Explicit Guard
const ProfileCard: React.FC = ({ profile }) => {
if (!profile) return null; // or a placeholder
return (
<div>
<img src={profile.avatarUrl} alt="avatar" />
<p>{profile.bio}</p>
</div>
);
};
Approach 2 – Nullish Coalescing
const ProfileCard: React.FC = ({ profile }) => (
<div>
<img src={profile?.avatarUrl ?? "default.png"} alt="avatar" />
<p>{profile?.bio ?? "No bio."}</p>
</div>
);
Both patterns are now type‑safe, and the compiler will flag any future unsafe accesses.
Trade‑offs and Limitations
- Third‑party typings: Some declaration files (
.d.ts) may not account for null safety, causing false positives. Updating the library or writing a small wrapper module can resolve these. - Compiler noise in large codebases: Turning on
strictNullCheckscan surface a burst of errors. Incremental adoption—enabling the flag in a new feature branch or on a subset of files—helps manage the transition. - Runtime performance: The flag has no runtime cost; it only influences compile‑time checks.
Actionable Checklist for Turning It On
- Add
"strictNullChecks": truetotsconfig.json. - Run
tsc --noEmitto surface errors. Do not commit until the build passes. - Fix errors by adding guards, nullish operators, or updating types.
- Use
tsc --skipLibChecktemporarily if third‑party libs cause noise. - Gradually enable
strictNullChecksacross the repo by merging feature branches that already comply. - Optional: Add
eslint-plugin @typescript-eslintrules such asno-unnecessary-type-assertionto reinforce the pattern.
Conclusion
Enabling strictNullChecks may feel like a one‑time refactor headache, but the payoff is a codebase that catches null dereferences before they reach production. IDE autocomplete becomes more accurate, and developers can reason about nullability with confidence. If you’re maintaining a legacy project, start small: pick a module, enable the flag, fix the errors, and then propagate the change. Over time, the entire codebase will benefit from clearer contracts and fewer runtime surprises.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.