Check if an Object implements an interface in TypeScript

avatar
Borislav Hadzhiev

Last updated: Jan 23, 2023
3 min

banner

# Check if an Object implements an interface in TypeScript

Use a user-defined type guard to check if an object implements an interface in TypeScript.

The user-defined type guard consists of a function that checks if the passed-in object contains specific properties and returns a type predicate.

index.ts
interface Employee { id: number; name: string; salary: number; } function isAnEmployee(obj: any): obj is Employee { return 'id' in obj && 'name' in obj && 'salary' in obj; } const emp: Employee = { id: 1, name: 'Bobby Hadz', salary: 100, }; console.log(isAnEmployee(emp)); // ๐Ÿ‘‰๏ธ true console.log(isAnEmployee({ id: 1 })); // ๐Ÿ‘‰๏ธ false if (isAnEmployee(emp)) { // ๐Ÿ‘‰๏ธ TypeScript knows that emp is type Employee console.log(emp.id); // ๐Ÿ‘‰๏ธ 1 console.log(emp.name); // ๐Ÿ‘‰๏ธ "Bobby Hadz" console.log(emp.salary); // ๐Ÿ‘‰๏ธ 100 }

check if object implements interface

We used a user-defined type guard to check if an object implements an interface.

The obj is Employee syntax is a type predicate where obj must be the name of the parameter the function takes.

If the isAnEmployee function returns true, TypeScript knows that the supplied value is of type Employee and allows us to access all properties and methods on the specific interface.

The example simply checks if the passed-in object contains the id, name and salary properties.

index.ts
function isAnEmployee(obj: any): obj is Employee { return 'id' in obj && 'name' in obj && 'salary' in obj; }
Depending on your use case, you might need to be more strict and check not only for the existence of the properties but also for the types of the values.

This can get pretty verbose if your interface has many properties.

# Check if an Object implements an interface by using a type property

An alternative approach is to add a type property to the interface, for which you check instead.

index.ts
interface Employee { id: number; name: string; salary: number; type: 'Employee'; // ๐Ÿ‘ˆ๏ธ add type property } function isAnEmployee(obj: any): obj is Employee { // ๐Ÿ‘‡๏ธ check for type property return 'type' in obj && obj.type === 'Employee'; } const emp: Employee = { id: 1, name: 'Bobby Hadz', salary: 100, type: 'Employee', }; console.log(isAnEmployee(emp)); // ๐Ÿ‘‰๏ธ true console.log(isAnEmployee({ id: 1 })); // ๐Ÿ‘‰๏ธ false if (isAnEmployee(emp)) { console.log(emp.id); // ๐Ÿ‘‰๏ธ 1 console.log(emp.name); // ๐Ÿ‘‰๏ธ "Bobby Hadz" console.log(emp.salary); // ๐Ÿ‘‰๏ธ 100 console.log(emp.type); // ๐Ÿ‘‰๏ธ "Employee" }

The Employee interface has a type property with the value of Employee.

This means that all objects that have a type of Employee will have this property.

All we have to do in the function is check if the passed-in object has a type property that's equal to Employee.

I've also written an article on how to create an object based on an interface.

# Working around interfaces that extend from other interfaces

However, note that this can get difficult to manage if you have interfaces that extend from Employee.

index.ts
interface Employee { id: number; name: string; salary: number; type: 'Employee'; // ๐Ÿ‘ˆ๏ธ add type property } // โ›”๏ธ Error: Interface 'Accountant' incorrectly // extends interface 'Employee'. // Types of property 'type' are incompatible. interface Accountant extends Employee { type: 'Accountant'; }

You can't simply override the type property in the Accountant interface.

If you have to do this, you'd get to set the type property to be a string, but this would be difficult to manage if you have deeply nested structures.

Want to learn more about working with interfaces in TypeScript? Check out these resources: How to set up TypeScript interface Default values,Declaring getters/setters in Interfaces and Classes in TS.

# A user-defined type guard is a better solution

User-defined type guards are very useful, especially when you have to check if an object is one of multiple types you know about in advance.

index.ts
interface Dog { bark(): void; } interface Cat { meow(): void; } const dog: Dog = { bark() { console.log('woof'); }, }; const cat: Cat = { meow() { console.log('meow'); }, }; function isDog(pet: Dog | Cat): pet is Dog { return 'bark' in pet; } function getPet(): Dog | Cat { return Math.random() > 0.5 ? dog : cat; } const pet = getPet(); if (isDog(pet)) { console.log(pet.bark()); } else { // ๐Ÿ‘‰๏ธ TypeScript knows pet is Cat console.log(pet.meow()); }

The isDog() function in the example takes a parameter of type Dog or Cat and checks if the passed-in parameter is a Dog.

Notice that we can access dog-specific properties in the if block and in the else block, TypeScript knows that if pet isn't a Dog, then it will be of type Cat.

I've also written an article on how to check if a property exists in an object.

If you need to get an object's key by value, click on the following link.

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.

Copyright ยฉ 2024 Borislav Hadzhiev