TypeScript · Types that pay for themselves

What is a type guard and when should you write one?

Mediumtype-guardsnarrowingvalidationUpdated Oct 2026
Quiz this track

Short answer

A type guard is a function or check that narrows a value's type within a conditional. User-defined guards return a type predicate such as value is User.

A type guard connects a runtime check to the type system. Built-in checks such as typeof and instanceof narrow automatically. A user-defined guard packages a reusable check in a function whose return type is a type predicate, so the compiler can narrow the argument after the call.

ts
type User = { id: number; name: string };

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

function greet(value: unknown): string {
  if (isUser(value)) {
    return "Hello, " + value.name;
  }
  return "Hello, guest";
}

Built-in and custom guards

  • typeof narrows primitives
  • instanceof narrows class instances
  • in narrows object variants by property presence
  • Array.isArray narrows arrays
  • A type predicate such as value is User narrows after a custom call

The predicate is a promise to the compiler. If the runtime check is incomplete, the body of the guard will be treated as a User even when it is not. For data from outside the program, validate every field you rely on, or use a schema library that returns a typed result.

A type predicate does not perform a cast and does not change the runtime value. It only refines what the compiler knows inside the guarded branch.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1How is a type guard different from a type assertion?
  2. 2What does the value is User return type mean?
  3. 3Can a type guard be async?
  4. 4When should you use a schema validator instead?

Say it in the interview

A type guard narrows a value inside a conditional. I write a user-defined guard with a type predicate when the check is reusable, such as isUser. Inside the guard I still have to validate the actual structure; the predicate is a promise to the compiler. I prefer guards over casts because the check runs at runtime and keeps the narrowing honest.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live TypeScript mock interview and get scored feedback on depth, clarity and confidence.