๐ŸŽ“ A1Learner
๐Ÿ”
0 of 42 lessons completed

TypeScript Type Predicates

A type predicate is a return type that names the narrowed type of a parameter. It lets one written check narrow values everywhere the check is reused.

Filtering without a predicate keeps the union

The callback is annotated to return a plain boolean. The filtered array keeps the union, and a string method on an element is refused.

const mixed: (string | number)[] = ["pen", 42, "pad", 7];
function keepText(v: string | number): boolean {
  return typeof v === "string";
}
const filtered = mixed.filter(keepText);
console.log(filtered[0].toUpperCase());

A predicate narrows the filtered array

The return type `v is string` is the predicate. Filter now returns a string array, and string methods work on every element.

function isText(v: string | number): v is string {
  return typeof v === "string";
}
const mixed: (string | number)[] = ["pen", 42, "pad", 7];
const words = mixed.filter(isText);
console.log(words.map((w) => w.toUpperCase()).join(", "));
console.log(words.length);

A predicate over object shapes

A predicate can narrow an object union by checking a shared tag member. Here the tag is the `kind` field.

type NoteEntry = { kind: "note"; text: string };
type CountEntry = { kind: "count"; value: number };
type Entry = NoteEntry | CountEntry;
function isNote(e: Entry): e is NoteEntry {
  return e.kind === "note";
}
const entries: Entry[] = [
  { kind: "note", text: "call supplier" },
  { kind: "count", value: 12 },
  { kind: "note", text: "send invoice" },
];
const notes = entries.filter(isNote);
console.log(notes.map((n) => n.text).join(" | "));

Example

function isScore(v: string | number | boolean): v is number {
  return typeof v === "number";
}
const raw: (string | number | boolean)[] = ["heat", 30, true, 12, "final", 8];
const scores = raw.filter(isScore);
const total = scores.reduce((sum, s) => sum + s, 0);
console.log(scores.join("+"));
console.log(total);

Key points

  • A predicate has the form `x is T`, where x is a parameter of the function.
  • A check that returns a plain boolean gives the caller no narrowed type.
  • `Array.filter` accepts a predicate and returns an array of the narrowed type.
  • The predicate function must return true exactly for values of the named type.
  • A predicate turns one written check into narrowing that follows the function.

In this example, the predicate isScore narrows the mixed array to a number array. The narrowed array can be joined and summed with no further checks.

Note

TypeScript trusts the predicate, so a wrong check narrows to a wrong type.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท TypeScript Playground

Exercise

A filter callback has the return type `v is string`. What type does filter return?