How to use the 'in' operator to narrow down the properties and methods of an object with union type in TypeScript?

November 13, 2021 - 4 min read

To narrow down the properties and methods of an object with union type we can use the in operator in TypeScript.

TL;DR

// Editor type
type Editor = {
  name: string;
};

// Admin type
type Admin = {
  name: string;
  role: string;
};

// function with parameter of user with
// union type composed of `Editor` and `Admin` type
function showRole(user: Editor | Admin) {
  // use the `in` operator to narrow down to the `Admin` type
  // since "role" property only exists in `Admin` type
  if ("role" in user) {
    console.log(user.role);
  } else {
    console.log("No user roles assigned");
  }
}

For example, let's make a type called Editor with a name property having the type of string and another type called Admin having name and role having the type of string like this,

// Editor type
type Editor = {
  name: string;
};

// Admin type
type Admin = {
  name: string;
  role: string;
};

Now let's make a function called showRole with a parameter of user with a union type composed of both the Editor and Admin types.

It may look like this,

// Editor type
type Editor = {
  name: string;
};

// Admin type
type Admin = {
  name: string;
  role: string;
};

// function with parameter of user with
// union type composed of `Editor` and `Admin` type
function showRole(user: Editor | Admin) {
  // cool code here... 🥳
}

Now the aim of the above function should be to show the role of the user to the console that will be passed down to the function parameter.

So let's try to access the role property in the user variable.

It can be done like this,

// Editor type
type Editor = {
  name: string;
};

// Admin type
type Admin = {
  name: string;
  role: string;
};

// function with parameter of user with
// union type composed of `Editor` and `Admin` type
function showRole(user: Editor | Admin) {
  // this will be an error ❌ 🤯.
  console.log(user.role); // Property 'role' does not exist on type 'Editor | Admin'.
}

As soon we try to access the role property from the user object variable, the TypeScript compiler shows us an error saying Property 'role' does not exist on type 'Editor | Admin'.

This is because TypeScript doesn't know which type to use for the user object variable when we access the role property. This is an error caused because the user object variable has a union type with Editor and Admin type and we haven't properly narrowed down the type we need to use here.

  • To narrow down to the correct type let's use the in operator. The in operator will check if a property or a method exists in a given object.

Since we need to show the role property which is present only in the Admin type, we can use the in operator and check to see if the role property exits in the given object.

It can be done like this,

// Editor type
type Editor = {
  name: string;
};

// Admin type
type Admin = {
  name: string;
  role: string;
};

// function with parameter of user with
// union type composed of `Editor` and `Admin` type
function showRole(user: Editor | Admin) {
  // use the `in` operator to narrow down to the `Admin` type
  // since "role" property only exists in `Admin` type
  if ("role" in user) {
    console.log(user.role);
  } else {
    console.log("No user roles assigned");
  }
}

Now inside the if block we can access all the properties and methods of the Admin type and the TypeScript compiler won't show the errors which is what we want to happen. 🥳

See the above code live in codesandbox.

Feel free to share if you found this useful 😃.