TypeScript Tutorial · TypeScript Basics · Lesson 9 of 25

TypeScript Narrowing

Refine union types with typeof, instanceof, in, equality and type predicates.

What is narrowing?

Inside an if, TypeScript narrows a union to the types that are possible in that branch:

Example 1Try it yourself
function lengthOf(value: string | string[] | null): number {
  if (value === null) return 0;
  if (typeof value === "string") return value.length;   // value: string
  return value.length;                                    // value: string[]
}
console.log(lengthOf("hello"), lengthOf(["a", "b"]), lengthOf(null));

Output

5 2 0

Narrowing techniques

Check Narrows by
typeof x === "string" primitive type
x instanceof Date class
"swim" in animal property existence
x === null, x !== undefined equality
Array.isArray(x) arrays
Example 2Try it yourself
type Fish = { swim: () => string };
type Bird = { fly: () => string };

function move(animal: Fish | Bird): string {
  if ("swim" in animal) return animal.swim();
  return animal.fly();
}
function when(value: Date | string): string {
  return value instanceof Date ? value.toISOString().slice(0, 10) : value;
}
console.log(move({ swim: () => "swimming" }), move({ fly: () => "flying" }));
console.log(when(new Date(Date.UTC(2026, 0, 2))), when("tomorrow"));

Output

swimming flying
2026-01-02 tomorrow

Type predicates

A function returning value is Type teaches TypeScript a custom check:

Example 3Try it yourself
interface User { id: number; name: string }

function isUser(value: unknown): value is User {
  return typeof value === "object" && value !== null && "id" in value && "name" in value;
}

const data: unknown = JSON.parse('{"id": 1, "name": "Ada"}');
if (isUser(data)) {
  console.log(`Valid user: ${data.name}`);
}
console.log(isUser({ id: 2 }));

Output

Valid user: Ada
false

Test yourself

What return type makes a function a type predicate?

  1. boolean
  2. value is User
  3. User | false
  4. asserts User
Show answer

Answer: value is User