Type Predicates

A Function's Return Type Tells TS How to Narrow

Type Predicates

A return type of `x is T` makes a function a user-defined type guard. TS narrows based on its return value.

4 min read Level 2/5 #typescript#type-predicates#narrowing
What you'll learn
  • Write a `x is T` predicate function
  • Recognize common library predicates
  • Use predicates to filter arrays

When you need narrowing logic that’s not a simple typeof / instanceof check, write a type predicate.

The Syntax

function isString(x: unknown): x is string {
  return typeof x === "string";
}

function describe(x: unknown) {
  if (isString(x)) {
    x.toUpperCase();   // ✓ TS knows x is string here
  }
}

The return type x is string is the magic. When the function returns true, TS narrows the argument to string in the calling code.

Object Predicates

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

function process(data: unknown) {
  if (isUser(data)) {
    console.log(data.name);  // ✓ data is User
  }
}

Useful when validating data from external sources (API responses, localStorage, JSON files).

Predicates in .filter()

The single nicest use:

const items: (string | null)[] = ["a", null, "b", null, "c"];

const cleaned: string[] = items.filter((x): x is string => x !== null);
// type is string[], not (string | null)[]

Without the predicate, .filter returns (string | null)[] — TypeScript can’t prove the filter actually removed nulls. The predicate gives it that guarantee.

Idiomatic Predicate

const isPresent = <T>(x: T | null | undefined): x is T =>
  x !== null && x !== undefined;

const items = [1, null, 2, undefined, 3];
const nums = items.filter(isPresent);   // number[]

A generic, reusable predicate for stripping nullish values.

The Trust Boundary

A predicate is only as honest as its implementation. TS doesn’t check that your code actually verifies the type — it just trusts the predicate’s return type. Bad predicates introduce silent bugs:

function isUser(x: unknown): x is User {
  return true;   // ✗ doesn't verify — TS still trusts you
}

Treat predicates as part of your API surface. Test them.

Up Next

When you know better than TS — assertions.

Assertions →