← Back to TypeScript Course | Chapter 8: Advanced Types | Lesson 6 of 20

Control Flow Analysis

Control flow analysis lets TypeScript track how values change type as code moves through conditions, returns, assignments, and other branches. This allows the compiler to narrow union types automatically.

Narrowing with typeof

TypeScript uses typeof checks inside conditional branches to narrow a primitive union type — inside an if (typeof x === "string") block, x is treated as exactly string for the rest of that branch.

Example: Narrowing with typeof

typescript
function print(x: string | number) {
  if (typeof x === "string") {
    console.log(x.toUpperCase());
  } else {
    console.log(x.toFixed(2));
  }
}
print("hello");

Truthiness Narrowing

TypeScript can eliminate null, undefined, false, 0, and other falsy possibilities from a type just by checking a value for truthiness in an if statement, without needing an explicit typeof or instanceof check.

Example: Truthiness Narrowing

typescript
function printLength(x: string | null | undefined) {
  if (x) {
    console.log(x.length);
  } else {
    console.log("no value");
  }
}
printLength("hello");
printLength(null);

Equality Narrowing

Equality checks narrow types too, especially useful when comparing a union value against one specific literal — after if (status === "error"), TypeScript knows status is exactly the literal type "error" in that branch.

Example: Equality Narrowing

typescript
type Status = "success" | "error" | "pending";
function handle(status: Status) {
  if (status === "error") {
    console.log("Something went wrong");
  } else {
    console.log("Status:", status);
  }
}
handle("error");

Assignments and Control Flow

TypeScript analyzes plain assignments as part of control flow, so a variable can be narrowed based on the value it currently holds even when its declared type is a much wider union.

Example: Assignments and Control Flow

typescript
let value: string | number;
value = "hello";
console.log(value.toUpperCase());
value = 42;
console.log(value.toFixed(1));

Narrowing Across Functions

Control flow analysis works together with return statements and type guards — once a branch returns or throws, TypeScript can use that fact to narrow the type in whatever code comes after it.

Example: Narrowing Across Functions

typescript
function process(x: string | null) {
  if (x === null) {
    return;
  }
  console.log(x.toUpperCase());
}
process("hello");
process(null);

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.