Q11 of 38 · TypeScript

How does TypeScript handle `null` and `undefined`, and what does `strictNullChecks` do?

TypeScriptJuniortypescriptnullundefinedstrict-null-checksnarrowingstrict-mode

Short answer

Short answer: With `strictNullChecks: true`, `null` and `undefined` are not assignable to other types — they must be explicitly included in a union (`string | null`). Without it, any value can be null, silently. Strict mode enables this flag by default, making null-safety enforced at compile time.

Detail

By default (without strictNullChecks), TypeScript allows null and undefined to be assigned to any type. This matches JavaScript's permissive behaviour but misses a whole class of runtime errors.

strictNullChecks: true: Null and undefined are their own distinct types. You cannot assign null to string — you must use string | null. Before using a nullable value, you must narrow it (if check, optional chaining, non-null assertion).

Narrowing null: TypeScript understands if (x !== null), if (x != null) (both null and undefined), optional chaining (x?.y), and nullish coalescing (x ?? default).

Non-null assertion (!): x! tells TypeScript "I know this is not null/undefined". It suppresses the null error but throws no runtime check — if you're wrong, you get a runtime error. Use sparingly and only when you have external knowledge the compiler lacks.

Strict mode: Enabling "strict": true in tsconfig turns on strictNullChecks (plus several other checks). This is the recommended baseline for all TypeScript projects including test suites.

In test automation: Playwright element handles (Locator | null), optional API response fields, and database query results all benefit from null-safe handling.

// EXAMPLE

// Without strictNullChecks (not recommended)
let name: string = null; // allowed! silent runtime bomb

// With strictNullChecks: true
let name2: string = null;        // Error!
let name3: string | null = null; // ok — explicit

// Narrowing
function getLength(s: string | null): number {
  if (s === null) return 0;
  return s.length; // TypeScript knows s is string here
}

// Optional chaining
const city = user?.address?.city; // undefined if any step is null

// Non-null assertion — use with care
const el = document.getElementById("btn")!; // "I know it exists"
el.click(); // no null check — runtime error if element missing

// API response with optional fields
interface ApiUser {
  id: number;
  deletedAt: string | null; // null = not deleted
}
function isDeleted(u: ApiUser): boolean {
  return u.deletedAt !== null;
}

// WHAT INTERVIEWERS LOOK FOR

Understanding that strictNullChecks is off by default and why that's dangerous. Narrowing patterns (if, optional chaining, nullish coalescing). The non-null assertion as an escape hatch with its risks. Recommending strict mode.

// COMMON PITFALL

Overusing the non-null assertion `!` to silence errors — every `!` is a bet that the value is non-null that TypeScript cannot verify. They accumulate into a pattern of ignoring nullability entirely.