Who Are You, Object? Getting the Class Name in TypeScript (Runtime)

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

Why Might You Need a Class Name at Runtime?

\n\n

Imagine: you're writing a complex system in TypeScript. You have a class hierarchy — User, Admin, Moderator. Somewhere deep in the code, you receive an object, but you don't know what it really is. You only see object in the console.

\n\n

Or you're building a logger that should output not just [Object], but a meaningful class name: [User: John]. Or you're writing a decorator that needs to decide how to handle an object based on its type.

\n\n

This is where the question with thousands of views on Stack Overflow comes to the rescue: "Get an object's class name at runtime". Today, we won't just give the answer; we'll look under the hood of TypeScript and JavaScript to understand how it actually works.

\n\n

Yes, TypeScript is a superset of JavaScript. All the type magic disappears after compilation. But the class name is not a type; it's a property of the prototype. And it stays with us at runtime.

\n\n

The Simplest Way: constructor.name

\n\n

If you've ever Googled this question, you've probably seen this one-liner:

\n\n
class User {\n  constructor(public name: string) {}\n}\n\nconst user = new User("Alice");\nconsole.log(user.constructor.name); // "User"
\n\n

Does it work? Yes. Is it fast? Yes. But there are nuances that can bite you if you don't know how it works.

\n\n

How Does It Work Under the Hood?

\n\n

Every object in JavaScript has a constructor property. This is a reference to the function that created the object. And any function (a class is also a function) has a name property.

\n\n

When you write user.constructor.name, the engine does the following:

\n
    \n
  • Walks up the prototype chain of the user object.
  • \n
  • Finds the constructor property on User.prototype.
  • \n
  • Reads the name of the constructor function User.
  • \n
\n\n

This is a cheap operation, but it's not free. In most cases, you won't even notice it.

\n\n

When Does constructor.name Fail?

\n\n

Here's a classic gotcha:

\n\n
const obj = Object.create(null);\nconsole.log(obj.constructor); // undefined\n// console.log(obj.constructor.name); // TypeError!
\n\n

An object created with Object.create(null) has no prototype. It has no constructor. Be careful.

\n\n

The second case is minification. If you use a bundler (Webpack, Terser) that renames classes, constructor.name might return something like t or e. This is only a problem for production, but it's good to know about.

\n\n

Alternative: instanceof and Custom Checks

\n\n

Sometimes you don't just need the name, but a check: "Is this object an instance of class X?"

\n\n
class Animal {}\nclass Dog extends Animal {}\n\nconst dog = new Dog();\n\nconsole.log(dog instanceof Dog);    // true\nconsole.log(dog instanceof Animal); // true\nconsole.log(dog instanceof Object); // true
\n\n

instanceof works through the prototype chain. It checks if Dog.prototype is in the prototype chain of the dog object. If yes — true.

\n\n

But instanceof doesn't give you a string with the name. It gives you a boolean value. This is not suitable for logging or serialization.

\n\n

Combining: Check + Name

\n\n

You can write a utility that first checks the type and then returns the name:

\n\n
function getClassName(obj: any): string | null {\n  if (obj === null || obj === undefined) return null;\n  if (typeof obj !== 'object' && typeof obj !== 'function') return null;\n\n  // Protection against Object.create(null)\n  if (!obj.constructor) return 'Object (no prototype)';\n\n  const name                

Blogs

Book Recommendations