StrictNullChecks in TypeScript

strictNullChecks makes null and undefined their own distinct types. Learn how it catches the most common runtime error in JavaScript and how to handle nullable values safely.

5 min read

In plain JavaScript, null and undefined can appear anywhere. You can pass them to any function, assign them to any variable, and access properties on values that might be missing.

When JavaScript encounters a null value where it expected an object, it throws a TypeError at runtime. This is the single most common source of production crashes in JavaScript applications.

The strictNullChecks flag in TypeScript makes null and undefined their own distinct types. When enabled, you cannot use them where a concrete value is expected. Every place a value might be missing becomes visible at compile time, not at 3 AM when your error tracker lights up.

What changes when you enable it

Without strictNullChecks, null and undefined are valid values for every type. This code compiles without any complaint:

typescripttypescript
let name: string;
name = "Alice";
name = null;
name = undefined;

All three assignments are accepted. The type annotation says string, but the compiler lets you put null and undefined in there anyway. This means every string variable in your program might actually be null, and the type system gives you no help discovering where.

With strictNullChecks enabled, the story changes. Null and undefined are no longer part of every type:

typescripttypescript
let name: string;
name = "Alice";  // OK
name = null;     // Error: Type 'null' is not assignable to type 'string'

The second assignment now produces a compile error. If you want a variable to accept null, you must declare it explicitly as a union type:

typescripttypescript
let name: string | null;
name = null;  // OK: null is part of the declared type

This makes the possibility of null visible in the type itself. Anyone reading the code knows this value might be absent.

The most common places it catches bugs

The flag surfaces nullability in many everyday APIs that can return missing values. Before strictNullChecks, these APIs silently pretend the value is always present. After, they tell the truth.

Array.find and Array.findIndex

The .find() method returns the first matching element or undefined if nothing matches. With strictNullChecks on, the return type includes undefined:

typescripttypescript
const users = [
  { name: "Alice", role: "admin" },
  { name: "Bob", role: "editor" },
];
 
const admin = users.find((u) => u.role === "superadmin");
console.log(admin.name);

The compiler flags the last line, because nothing in the array has the role "superadmin" so the search can come back empty. Here is the exact error:

texttext
'admin' is possibly 'undefined'.

Admin might be undefined because no user has the role "superadmin". You must handle the missing case before accessing properties on the result.

Map.get

The .get() method on a Map returns the value or undefined if the key does not exist. With strictNullChecks on, every .get() call produces a type that includes undefined, forcing you to check the result.

Optional properties

When you access an optional property on an object, TypeScript includes undefined in the type. The compiler requires a check before you use the value in a context that does not accept undefined.

DOM queries

document.querySelector returns an element or null. With strictNullChecks enabled, you cannot call methods on the result without checking for null first. This catches cases where a CSS selector does not match any element.

How to handle nullable values

Once strictNullChecks is on, you need patterns for working with values that might be null or undefined. TypeScript provides several tools that make this safe and readable.

Narrowing with if checks

The simplest pattern: check for null or undefined before using the value. TypeScript narrows the type inside the if block:

typescripttypescript
const admin = users.find((u) => u.role === "admin");
 
if (admin !== undefined) {
  console.log(admin.name); // admin is narrowed to the user type here
}

After the check, TypeScript knows admin is not undefined, so accessing .name is safe.

Optional chaining

When you only need a property and do not care whether the parent is null, use optional chaining. If the left side is null or undefined, the whole expression evaluates to undefined instead of throwing:

typescripttypescript
const adminName = users.find((u) => u.role === "admin")?.name;

If .find() returns undefined, adminName becomes undefined instead of causing a runtime error. The type of adminName is string | undefined, so downstream code still needs to handle the missing case.

Nullish coalescing

When you want a fallback value, use the nullish coalescing operator. It returns the right side only when the left side is null or undefined:

typescripttypescript
const adminName = users.find((u) => u.role === "admin")?.name ?? "No admin found";

Now adminName is always a string. The fallback kicks in whenever the find or the name access produces null or undefined.

How it fits into strict mode

strictNullChecks is one of the flags enabled by setting strict to true. It works hand in hand with noImplicitAny: one makes sure every value has a known type, the other makes sure null and undefined are handled within that type system.

In the nine-flag strict family, strictNullChecks and noImplicitAny are the two that most directly change how you write code day to day. For the full picture, see strict mode in TypeScript. To understand how the other half of the pair works, read about noImplicitAny in TypeScript.

Rune AI

Rune AI

Key Insights

  • strictNullChecks makes null and undefined their own types, not assignable to everything.
  • Without it, null and undefined silently flow through your code and cause runtime crashes.
  • Array.find(), Map.get(), and optional properties all return T | undefined with this flag on.
  • Use if checks, optional chaining, and nullish coalescing to handle nullable values.
  • This flag is part of strict mode but can be toggled individually.
RunePowered by Rune AI

Frequently Asked Questions

What is the difference between null and undefined with strictNullChecks?

With strictNullChecks enabled, null and undefined are distinct types. null is its own type, and undefined is its own type. A variable typed as string cannot be null or undefined unless you explicitly include them in a union like string | null.

Why does array.find() return T | undefined?

Because find() may not locate a matching element. Without strictNullChecks, TypeScript hides this fact and lets you use the result as if it were always found. With strictNullChecks, the return type includes undefined, forcing you to check the result before using it.

How do I handle a value that might be null?

Use a type guard like an if check (if (value !== null)), optional chaining (value?.property), or the nullish coalescing operator (value ?? fallback). TypeScript narrows the type after a null check, so the value is treated as non-null inside the if block.

Conclusion

strictNullChecks is arguably the most impactful single flag in TypeScript. It forces you to acknowledge that values can be missing and to handle those cases explicitly. The result is code that crashes far less often at runtime because null and undefined are caught at compile time instead.