Skip to content
TypeScript ts config 3 min read

strict, strictNullChecks & noImplicitAny

The strict family of compiler options is where TypeScript earns its reputation for catching bugs before they ship. strict is a single switch that turns on a whole set of stricter checks at once; strictNullChecks and noImplicitAny are the two most consequential members of that set. Without them, TypeScript is a much weaker linter that silently allows null dereferences and untyped values. This page explains the umbrella flag, the key sub-flags, and why enabling strict mode from day one is the single best configuration decision you can make.

The strict umbrella flag

Setting strict: true enables every check in the strict family in one line, and TypeScript automatically opts new strictness flags into this group as the language evolves. It is the recommended baseline for all new projects.

{
  "compilerOptions": {
    "strict": true
  }
}

strict currently turns on strictNullChecks, noImplicitAny, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, useUnknownInCatchVariables, and alwaysStrict. You can still override any individual member after enabling the umbrella.

What strict enables

Each sub-flag closes a different category of unsafe behavior. The table summarizes the most important ones.

FlagCatches
strictNullChecksUsing possibly null/undefined values
noImplicitAnyValues that silently become any
strictFunctionTypesUnsafe function parameter variance
strictPropertyInitializationClass fields never assigned
noImplicitThisthis with an implicit any type
useUnknownInCatchVariablescatch (e) typed as any instead of unknown

You can disable a single member while keeping the rest, e.g. "strict": true with "strictPropertyInitialization": false, though doing so should be a deliberate, documented exception.

strictNullChecks

This is the highest-impact flag. With it off, null and undefined are assignable to every type, so the compiler cannot warn you about the most common runtime crash in JavaScript. With it on, nullable values must be handled explicitly.

function getLength(s: string | null): number {
  // ❌ Error: 's' is possibly 'null'.
  return s.length;
}

function getLengthSafe(s: string | null): number {
  if (s === null) return 0;
  return s.length; // ✅ narrowed to string here
}

Once null checks are on, the type system forces you to narrow before access — via a guard, optional chaining (s?.length), or a nullish default (s ?? ""). This eliminates an entire class of “cannot read property of undefined” errors.

noImplicitAny

When the compiler cannot infer a type and you have not annotated one, it falls back to any. noImplicitAny turns that silent fallback into an error, forcing you to either annotate or let inference produce a real type.

// ❌ Error: Parameter 'item' implicitly has an 'any' type.
function total(items) {
  return items.reduce((sum, item) => sum + item.price, 0);
}

// ✅ Annotated — full type checking restored
function totalSafe(items: { price: number }[]): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

Implicit any is contagious: one untyped parameter disables checking for everything derived from it. noImplicitAny keeps those holes from opening in the first place.

Migrating an existing codebase

Flipping strict: true on a large legacy project can surface hundreds of errors at once. Enable members incrementally instead, starting with noImplicitAny, then strictNullChecks, fixing each batch before moving on.

// Step-by-step adoption for an existing project
{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": false
  }
}

Turn strict: true on for every new project from the first commit. Retrofitting strictness later is far more painful than living with it from the start, because unsafe patterns accumulate quickly.

Best Practices

  • Set strict: true in every new project — it is the modern TypeScript baseline.
  • Treat strictNullChecks as non-negotiable; it prevents the most common runtime crashes.
  • Keep noImplicitAny on so untyped values are errors, not silent any holes.
  • Handle nullable values with guards, optional chaining (?.), or nullish coalescing (??).
  • Migrate legacy code one strict flag at a time rather than enabling everything at once.
  • Disable individual strict members only as a documented, temporary exception.
  • Combine strict mode with noUncheckedIndexedAccess for even tighter array/record safety.
Last updated June 29, 2026
Was this helpful?