Ch. 2 · TypeScript

TypeScript Strict Compiler Flags

Turn on strict checks, know which flags strict bundles, and layer the non-strict extras such as noUncheckedIndexedAccess.

~2 min readintermediateupdated Oct 5, 2026

The strict flag is a bundle of checks, not a single one. Turning it on catches nullability, implicit any and function-assignment mistakes, but a few high-value checks live outside the bundle and must be enabled separately.

Before you start

You should be comfortable with a tsconfig.json and have some experience fixing type errors. This article explains what the main flags do and how to adopt them without a huge migration.

Step-by-step walkthrough

Step 1: Use strict as the baseline

"strict": true enables strictNullChecks, noImplicitAny, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis and alwaysStrict. Together they make null and undefined distinct from other types and require explicit parameter types, which is where most of the value comes from.

Step 2: Add the extras that strict leaves out

noUncheckedIndexedAccess makes every index and array lookup possibly undefined. exactOptionalPropertyTypes stops undefined from being assigned to an optional property unless declared. noImplicitOverride and noFallthroughCasesInSwitch catch smaller mistakes. These are not in strict because they are noisier.

Step 3: Adopt incrementally without losing coverage

For an existing codebase, turn on strict and fix errors file by file, or start with the highest-value flag (strictNullChecks) and widen over time. Avoid scattering any to silence errors, which defeats the purpose; use unknown at boundaries and narrow.

Worked scenario

The config shows the bundle plus the two extras worth adding.

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true
  }
}
JSON

Walk through the example

With strict on, function f(x) {} now errors because x is implicitly any, and a possibly-null value cannot be used without a check. Adding noUncheckedIndexedAccess means items[0] is T | undefined, so you handle the empty case explicitly. exactOptionalPropertyTypes makes { name: undefined } invalid for { name?: string } unless undefined is allowed.

Common mistake

Assuming strict covers index access; it does not, so arr[0] is typed T and a runtime undefined sneaks through. Another mistake is enabling exactOptionalPropertyTypes without realising it changes the meaning of optional properties, breaking code that passes explicit undefined.

Verify the behavior

Introduce one error per flag and confirm each is reported: an implicit any parameter, a possibly-null dereference, an unchecked index result, and an explicit undefined for an exact optional property. Then fix each minimally and confirm the file compiles, which demonstrates what each flag actually enforces.

Interview exercise

A team enables strict but still ships crashes from array[0] being undefined. Which flag is missing, and what is the fix?

Answer and reasoning

noUncheckedIndexedAccess is missing: without it, index and array access is typed as if a value always exists. Enable it and handle the undefined case, usually with an early return, a default, or a length check. This converts a class of runtime crashes into compile-time errors without changing runtime behavior.

Continue learning

See the flow consequences in strict null flow and optional property presence. Read the TypeScript tsconfig reference and try the TypeScript MCQs.

More in TypeScript

read ✓TypeScript · hard

TypeScript Abstract Classes and Contracts

Share behavior with abstract classes, enforce required members, and decide when an interface or composition is the better contract.

~2 min readread →
esc