Skip to content
masterclassBuddyTech Buzz5 fresh blogs · 5:00 AM IST

TypeScript · Function

Type Guards

Type guards are runtime checks that TypeScript uses to narrow a value to a more specific type along control-flow paths. Use built-in JavaScript checks or a user-defined predicate for custom object validation.

How it works

A type guard is a runtime-checking expression that lets TypeScript refine a value’s declared type along control-flow paths. Built-in checks such as typeof, equality, in, and instanceof narrow unions, while a function returning a type predicate communicates a custom refinement.

Syntax

function isType(value: UnknownType): value is SpecificType { return /* runtime check */; }

Parameters

NameTypeDescription
valueunknown or a union typeThe value being tested; for a custom predicate, the parameter name appears on the left side of is.

Returns

Built-in guards refine types in control-flow branches; a user-defined guard returns boolean and declares a predicate such as value is Type to communicate the refinement.

Key points

  • Narrowing is control-flow-sensitive: the checker tracks execution paths and uses successful checks to choose the most specific type at each point.
  • Comparing typeof with a recognized runtime category narrows the checked value.
  • Equality comparisons and switch cases can refine union members, including discriminated unions.
  • The in operator separates union members by whether the tested property exists, with different refinements in true and false branches.
  • Custom guards expose their refinement through a predicate return annotation such as value is SpecificType.
  • Calling a predicate guard narrows the argument when its declared type can be refined to the predicate target.
  • Methods and interfaces can use a this-based predicate to refine the receiver inside narrowing positions.

Common mistakes

  • A user-defined predicate must name a parameter from that function’s signature; an arbitrary expression cannot appear before is.
  • Use instanceof with a constructor function, not an interface or an ordinary non-constructor value.

Example: A user-defined type guard

type Fish = { swim: () => void };
type Bird = { fly: () => void };

type Animal = Fish | Bird;

function isFish(animal: Animal): animal is Fish {
  return "swim" in animal;
}

function move(animal: Animal): void {
  if (isFish(animal)) {
    animal.swim();
  } else {
    animal.fly();
  }
}

move({ swim: () => console.log("swimming") });

The predicate return type tells TypeScript that a true result narrows the argument to Fish.

When to use it

Branch on primitive categories with typeof

A variable has a union of primitive types and operations differ by member.

Select object variants with in, equality, or switch

A union’s members differ by a property or discriminant.

Create a user-defined predicate

A domain-specific runtime check is needed for a structural type.

Narrow a class receiver with this is Type

A class method can validate and refine its own state.

Interview questions

QWhat is a type guard, and how does it relate to narrowing?

TypeScript treats checks such as typeof, equality, in, and instanceof as type guards and narrows a value on the corresponding control-flow path. The refinement is compile-time, while the check itself follows JavaScript runtime behavior.

Follow-up: How would you narrow a union of structural object types? Use a discriminating property or the in operator, or write a user-defined predicate when the check needs custom logic.

QHow do you write a custom type guard?

A user-defined guard is a function whose return type is a predicate such as value is Fish. When the function returns true, TypeScript narrows the passed variable to the predicate’s type, provided the original type is compatible.

Follow-up: What constraint applies to the predicate’s left side? It must be the name of a parameter in the current function signature.

QHow do built-in type guards differ?

typeof checks compare against JavaScript’s recognized result strings, while instanceof uses a constructor’s runtime prototype information. The in operator narrows a union according to whether a property is present.

Follow-up: When should a custom predicate be preferred? Use one when built-in JavaScript checks do not express the object-level validation needed by the program.

  • Narrowing
  • typeof type guards
  • Equality narrowing
  • in operator
  • instanceof
  • User-defined type guards
  • Type predicates
  • Assertion functions

Source: Documentation - Narrowing. Checked 2026-10-15.