Typing Classes in TypeScript: How to Check an Object's Type

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

How to Check a Class Type in TypeScript: From Beginner to Pro

\n\n

Have you ever written code in TypeScript, received an object of an unknown type, and thought: "Who are you, really?"? This question plagues thousands of developers — it's no wonder the topic of class type check in TypeScript has garnered hundreds of thousands of views on Stack Overflow. And today, we will finally figure out how to properly check class types in TypeScript.

\n\n

In this article, you will learn:

\n
    \n
  • Why typeof doesn't work for classes
  • \n
  • How to use instanceof like a Swiss Army knife
  • \n
  • What type guards are and how they save your code
  • \n
  • How to write your own type check using is
  • \n
  • Real-world practical examples
  • \n
\n\n

Let's go!

\n\n

The Problem: Why is typeof Powerless Here?

\n\n

In JavaScript, there is the typeof operator, which works perfectly with primitives:

\n\n
typeof "hello" // "string"\ntypeof 42      // "number"\ntypeof true    // "boolean"
\n\n

But when it comes to classes, typeof falls short:

\n\n
class Dog {}\nclass Cat {}\n\nconst pet = new Dog();\n\ntypeof pet; // "object" — useless!\ntypeof Dog; // "function" — not what we need either
\n\n

Why? Because classes in JavaScript are just syntactic sugar over constructor functions. typeof only sees "object" or "function" but doesn't distinguish which specific class it is.

\n\n

This is where class type check in TypeScript comes into play — a whole arsenal of tools that will help you accurately determine which class instance you are dealing with.

\n\n

Method 1: instanceof — Your Main Helper

\n\n

The most direct and understandable way to check a class type is the instanceof operator. It checks whether the class exists in the object's prototype chain:

\n\n
class Animal {\n  name: string;\n  constructor(name: string) {\n    this.name = name;\n  }\n}\n\nclass Dog extends Animal {\n  bark() {\n    console.log("Woof!");\n  }\n}\n\nclass Cat extends Animal {\n  meow() {\n    console.log("Meow!");\n  }\n}\n\nfunction handleAnimal(animal: Animal) {\n  if (animal instanceof Dog) {\n    // TypeScript knows that animal is a Dog\n    animal.bark();\n  } else if (animal instanceof Cat) {\n    animal.meow();\n  } else {\n    console.log(`Unknown animal: ${animal.name}`);\n  }\n}\n\nconst rex = new Dog("Rex");\nhandleAnimal(rex); // "Woof!"
\n\n

Notice: after the animal instanceof Dog check, TypeScript automatically narrows the type (type narrowing) and allows you to call Dog methods without errors. This is the magic of type guards — built-in type protectors.

\n\n

When does instanceof not work?

\n
    \n
  • When working with different windows/frames (different global objects)
  • \n
  • If classes are defined in different modules with different versions
  • \n
  • When checking interfaces (they don't exist at runtime)
  • \n
\n\n

Method 2: Custom Type Guards with the is Operator

\n\n

Sometimes instanceof is not enough. For example, you might want to check not only the class but also additional conditions. This is where custom type guards with the is keyword come to the rescue:

\n\n
interface Bird {\n  fly(): void;\n  layEggs(): void;\n}\n\ninterface Fish {\n  swim(): void;\n  layEggs(): void;\n}\n\nfunction isFish(pet: Bird | Fish): pet is Fish {\n  return (pet as Fish).swim !== undefined;\n}\n\nfunction move(pet: Bird | Fish) {\n  if (isFish(pet)) {\n    // TypeScript knows: pet is a Fish\n    pet.swim();\n  } else {\n    pet.fly();\n  }\n}
\n\n

Notice the syntax: pet is Fish in the return type. This tells TypeScript: "If this function returns true, then the parameter pet is a Fish." Now TypeScript will narrow the type everywhere you use

Blogs

Book Recommendations