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
inoperator checks whether a property exists. - It is useful for narrowing object unions.
- It works best with unique properties.
- Optional properties may still have
undefinedvalues. - With
unknown, check for object and non-null first.
Next up, we will learn instanceof Narrowing →.