TYPESCRIPT

TypeScript Type Guard: Syntax, Usage, and Examples

A TypeScript type guard is a function or construct that lets you check and narrow down types at runtime. It helps you ensure that variables or values conform to expected types before performing operations on them. Type guards improve type safety, prevent runtime errors, and make code more predictable.

How to Use Type Guards in TypeScript

A type guard is a function that returns a boolean value based on whether a given value matches a specific type. The most common syntax follows this pattern:

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

You can use this function inside conditional statements to narrow the type of a variable:

function printLength(value: unknown) {
  if (isString(value)) {
    console.log(value.length); // TypeScript knows 'value' is a string here
  } else {
    console.log("Value is not a string");
  }
}

printLength("Hello"); // Output: 5
printLength(42); // Output: Value is not a string

Using typeof for Primitive Type Guards

The typeof operator is useful for checking primitive types:

function isNumber(value: unknown): value is number {
  return typeof value === "number";
}

console.log(isNumber(10)); // true
console.log(isNumber("hello")); // false

Using instanceof for Object Type Guards

To check whether a value is an instance of a class or a specific object type, use instanceof:

class Dog {
  bark() {
    console.log("Woof!");
  }
}

function isDog(obj: unknown): obj is Dog {
  return obj instanceof Dog;
}

const pet = new Dog();
console.log(isDog(pet)); // true

When to Use Type Guards in TypeScript

Type guards are useful when working with:

  • Union types: If a variable can hold multiple types, type guards ensure that you correctly handle each case.
  • Custom type checks: When TypeScript’s built-in type inference is insufficient, type guards help define custom logic to differentiate types.
  • Filtering arrays: You can filter arrays based on type-specific conditions.

Type guards help prevent runtime errors caused by incorrect type assumptions.

Examples of Type Guards in TypeScript

Checking for Specific Types in a Union

You often need to determine the actual type of a variable before working with it. Type guards make this easier:

function processInput(input: string | number) {
  if (typeof input === "string") {
    console.log(`String length: ${input.length}`);
  } else {
    console.log(`Number squared: ${input * input}`);
  }
}

processInput("Hello"); // Output: String length: 5
processInput(5); // Output: Number squared: 25

Custom Type Guards for Objects

When working with objects that have different structures, you can define custom type guards:

interface Car {
  make: string;
  model: string;
}

interface Bicycle {
  brand: string;
  gearCount: number;
}

function isCar(vehicle: Car | Bicycle): vehicle is Car {
  return (vehicle as Car).make !== undefined;
}

const myCar: Car = { make: "Toyota", model: "Corolla" };
const myBike: Bicycle = { brand: "Giant", gearCount: 21 };

console.log(isCar(myCar)); // true
console.log(isCar(myBike)); // false

Filtering an Array with a Type Guard

A type guard can filter arrays to ensure only values of a certain type remain:

function isStringArray(value: unknown[]): value is string[] {
  return value.every((item) => typeof item === "string");
}

const mixedArray: (string | number)[] = ["apple", "banana", 42, "grape"];

const stringArray = mixedArray.filter((item): item is string => typeof item === "string");

console.log(stringArray); // Output: ["apple", "banana", "grape"]

Using Type Guards for Enums

Type guards also work with enums to restrict values to a specific subset:

enum UserRole {
  Admin = "admin",
  User = "user",
}

function isAdmin(role: UserRole): role is UserRole.Admin {
  return role === UserRole.Admin;
}

const userRole: UserRole = UserRole.User;

if (isAdmin(userRole)) {
  console.log("User has admin privileges");
} else {
  console.log("User is not an admin");
}

Learn More About Type Guards in TypeScript

Generic Type Guards

If you need a type guard that works for multiple types, use a generic function:

function isArrayOfType<T>(arr: unknown[], checkFn: (item: unknown) => item is T): arr is T[] {
  return arr.every(checkFn);
}

function isNumber(value: unknown): value is number {
  return typeof value === "number";
}

const values: unknown[] = [1, 2, "hello", 4];

if (isArrayOfType<number>(values, isNumber)) {
  console.log("All elements are numbers");
} else {
  console.log("Not all elements are numbers");
}

Type Guards for Interfaces

When dealing with interfaces, type guards help verify object properties:

interface Person {
  name: string;
  age: number;
}

function isPerson(obj: any): obj is Person {
  return typeof obj.name === "string" && typeof obj.age === "number";
}

const user = { name: "Alice", age: 25 };
console.log(isPerson(user)); // true

Using Type Guards with Type Assertions

Sometimes, you may need to use a type assertion to guide TypeScript:

function isDefined<T>(value: T | undefined | null): value is T {
  return value !== undefined && value !== null;
}

const data: (string | null)[] = ["Hello", null, "World"];

const filteredData = data.filter(isDefined);
console.log(filteredData); // Output: ["Hello", "World"]

Type Guards vs. Type Assertions

While type guards provide runtime checks, type assertions (as Type) override TypeScript’s type system without checking values. Type guards are safer because they prevent incorrect assumptions:

const unknownValue: unknown = "Hello";

// Unsafe: Type assertion without validation
const unsafeString: string = unknownValue as string;

// Safe: Using a type guard
if (isString(unknownValue)) {
  const safeString: string = unknownValue;
  console.log(safeString); // Output: Hello
}

Type Guards for String Literals

If you need to check whether a value matches a specific string literal, use a type guard:

type Color = "red" | "green" | "blue";

function isColor(value: unknown): value is Color {
  return value === "red" || value === "green" || value === "blue";
}

const userColor: string = "red";

if (isColor(userColor)) {
  console.log(`Valid color: ${userColor}`);
} else {
  console.log("Invalid color");
}

TypeScript type guards let you refine types at runtime, making your code safer and reducing type errors. They are essential when working with union types, dynamic objects, or complex data structures.

Learn TypeScript for Free
Start learning now
button icon
To advance beyond this tutorial and learn TypeScript by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH