TypeScript Strict Mode Reference
The strict flag in tsconfig.json enables a family of stricter type-checking options. Each catches a different class of bugs.
Enabling Strict Mode
{
"compilerOptions": {
"strict": true
}
}
This is equivalent to enabling all of the following flags individually.
Individual Flags
strictNullChecks
Makes null and undefined their own types instead of being assignable to everything.
// Without: compiles fine, crashes at runtime
const el = document.getElementById("app"); // HTMLElement | null
el.textContent = "hello"; // no error, but runtime crash if null
// With: forces null check
const el = document.getElementById("app");
if (el) el.textContent = "hello"; // safe
Impact: High. This is the single most valuable strict flag.
noImplicitAny
Errors when TypeScript cannot infer a type and falls back to any.
// Error: Parameter 'x' implicitly has an 'any' type
function double(x) { return x * 2; }
// Fix: add type annotation
function double(x: number) { return x * 2; }
strictFunctionTypes
Enforces contravariant parameter checking for function types.
type Handler = (event: MouseEvent) => void;
// Error: Event is not assignable to MouseEvent
const handler: Handler = (event: Event) => { };
strictBindCallApply
Type-checks bind, call, and apply calls.
function greet(name: string) { return `Hello, ${name}`; }
greet.call(null, 42); // Error: number is not assignable to string
strictPropertyInitialization
Class properties must be initialized in the constructor or with a default.
class User {
name: string; // Error: not initialized
email: string = ""; // OK
age: string;
constructor() {
this.age = "25"; // OK: initialized in constructor
}
}
Use the definite assignment assertion ! only when you're sure:
name!: string; // "trust me, this will be set"
noImplicitThis
Errors when this has an implicit any type.
// Error: 'this' implicitly has type 'any'
function getName() { return this.name; }
// Fix: declare this parameter
function getName(this: { name: string }) { return this.name; }
alwaysStrict
Emits "use strict" in every output file and parses in strict mode.
useUnknownInCatchVariables
Types catch clause variables as unknown instead of any.
try { /* ... */ } catch (e) {
// e is unknown — must narrow before using
if (e instanceof Error) console.log(e.message);
}
Migration Strategy
- Start with
"strict": false
- Enable
strictNullChecks first (biggest impact, most errors)
- Fix all null-check errors
- Enable
noImplicitAny
- Enable remaining flags one at a time
- Switch to
"strict": true and remove individual flags
Tip: Use // @ts-expect-error sparingly as a migration aid, with a TODO comment to fix later.