runtime.boot

Full Stack Systems
Production Mindset

CodeWithMihir

Engineering thoughtful products from interface to infrastructure.

CodeWithMihir

TypeScript Tutorial

TypeScript in Operator Narrowing Explained

Learn how the in operator narrows object union types in TypeScript, with practical examples, optional properties, and common mistakes.

Welcome back! I am Mihir, and in this lesson we will learn in operator narrowing in TypeScript.

The in operator checks whether a property exists in an object.


The Problem

type Admin = {
  name: string;
  permissions: string[];
};

type Customer = {
  name: string;
  orders: number;
};

function describeUser(user: Admin | Customer) {
  console.log(user.permissions);
}

This is invalid because Customer does not have permissions.


Basic in Narrowing

function describeUser(user: Admin | Customer) {
  if ("permissions" in user) {
    console.log(user.permissions);
  } else {
    console.log(user.orders);
  }
}

Inside the if, TypeScript knows user is Admin.

Inside the else, TypeScript knows user is Customer.


Another Example

type EmailNotification = {
  email: string;
  subject: string;
};

type SmsNotification = {
  phone: string;
  message: string;
};

function send(notification: EmailNotification | SmsNotification) {
  if ("email" in notification) {
    console.log(notification.subject);
  } else {
    console.log(notification.phone);
  }
}

The property check tells TypeScript which object shape you have.


Works Best with Unique Properties

The in operator is most useful when each union member has a unique property.

type Cat = {
  meow: () => void;
};

type Dog = {
  bark: () => void;
};

function speak(pet: Cat | Dog) {
  if ("meow" in pet) {
    pet.meow();
  } else {
    pet.bark();
  }
}

Optional Properties

Be careful with optional properties.

type User = {
  name: string;
  email?: string;
};

function hasEmail(user: User) {
  if ("email" in user) {
    console.log(user.email);
  }
}

The property may exist, but its value can still be undefined.

If you need a real string, check the value too.

if (typeof user.email === "string") {
  console.log(user.email.toLowerCase());
}

in Operator with Unknown Objects

When using unknown, first make sure the value is an object.

function printId(value: unknown) {
  if (typeof value === "object" && value !== null && "id" in value) {
    console.log(value.id);
  }
}

The value !== null check is important because typeof null is "object".


Quick Recap

  • The in operator checks whether a property exists.
  • It is useful for narrowing object unions.
  • It works best with unique properties.
  • Optional properties may still have undefined values.
  • With unknown, check for object and non-null first.

Next up, we will learn instanceof Narrowing →.