Skip to main content

The in operator when checking a union

What the in operator does when checking a union type

The in operator checks whether the given property exists on an object, and if it does, TypeScript narrows the type to the union variant where that property is defined.

In simpler terms: in helps TypeScript "understand" which exact object type is currently in front of it.


Example 1. The classic case

javascript
type User = { name: string }; type Admin = { name: string; permissions: string[] }; function printInfo(person: User | Admin) { if ("permissions" in person) { // Here person: Admin console.log("Permissions:", person.permissions); } else { // Here person: User console.log("User:", person.name); } }

TypeScript analyzes the union:

  • User does not contain permissions
  • Admin contains permissions
  • so inside the if, TS narrows the type to Admin

Example 2. Several possible types in a union

javascript
type Circle = { radius: number }; type Rectangle = { width: number; height: number }; type Shape = Circle | Rectangle; function area(shape: Shape) { if ("radius" in shape) { // shape: Circle return Math.PI * shape.radius ** 2; } else { // shape: Rectangle return shape.width * shape.height; } }

TypeScript understands: if the object has radius, then it is a Circle, otherwise it is a Rectangle.


Example 3. Complex types with several unique properties

javascript
type Cat = { meow: () => void }; type Dog = { bark: () => void }; type Animal = Cat | Dog; function makeSound(animal: Animal) { if ("bark" in animal) { // animal: Dog animal.bark(); } else { // animal: Cat animal.meow(); } }

A great way to tell apart similar types without a discriminant field.


Example 4. Checking nested objects

The in operator also works with nested objects:

javascript
type Employee = { info: { position: string } }; type Contractor = { company: string }; function describe(person: Employee | Contractor) { if ("info" in person) { console.log("Employee:", person.info.position); } else { console.log("Contractor:", person.company); } }

Important

  1. The in operator does not check the value, only whether the property exists on the object.
javascript
const obj = { x: undefined }; console.log("x" in obj); // true (the property exists, even though it is undefined)
  1. The check only works with objects (not primitives):
javascript
"length" in "hello"; // true "x" in 42; // error: number is not an object

When to use in

WhenWhy
In union types with different sets of propertiesGreat at telling data shapes apart
When there is no common discriminant field (kind)An alternative to discriminated unions
In custom type guard functionsCan be embedded in return "prop" in obj

Example of a custom Type Guard based on in

javascript
type User = { name: string }; type Admin = { name: string; permissions: string[] }; function isAdmin(person: User | Admin): person is Admin { return "permissions" in person; } function print(person: User | Admin) { if (isAdmin(person)) { console.log("Admin:", person.permissions); } else { console.log("User:", person.name); } }

Here return "permissions" in person; helps TypeScript determine that the isAdmin function guarantees the type Admin.


SUMMARY

What in doesChecks whether the object has the property
Syntax"propertyName" in object
Returnstrue if the property exists
Typing effectNarrows the union type to the variant where the property exists
Works withObjects and classes
Common useFor distinguishing union type variants (`User

In short:

The in operator is a built-in Type Guard that helps TypeScript determine which type from the union is currently in use, by checking whether a given property exists on the object.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.