TypeScriptUnions and narrowing
The in operator
Narrows a union of objects by checking whether an object has a given property.
Example
#TypeScript
type EmailContact = { name: string; email: string }
type PhoneContact = { name: string; phone: string }
function contactLine(contact: EmailContact | PhoneContact): string {
if ('email' in contact) return `${contact.name}: ${contact.email}`
return `${contact.name}: phone ${contact.phone}`
}
console.log(contactLine({ name: 'Ania', email: 'ania@codeworlds.pl' }))
console.log(contactLine({ name: 'Kuba', phone: '+48 600 100 200' }))Result
Ania: ania@codeworlds.pl Kuba: phone +48 600 100 200
Definition and usage
#The in operator checks whether an object has a property with the given name. In TypeScript it narrows unions of objects that have no shared tag: after if ("email" in contact) the compiler knows it’s the variant with the email field.
It’s handy when variants differ by their set of fields and have no kind field. If you can change the data structure, a discriminated union is usually easier to read.
Since TypeScript 4.9, the in operator also narrows values of type object and unknown: after the check the compiler knows the property exists, although its type is unknown.
Syntax
#Syntax
if ("field" in object) {
// object has the field
}Good practices
#- The
inoperator also checks inherited properties. To check only an object’s own fields, useObject.hasOwn(). - When the number of variants grows, turn them into a discriminated union with a
kindfield.
Related entries
#- Type narrowingDetermining a more precise type for a value based on checks in your code.
- Discriminated unionsUnions of objects with a shared tag field that makes it easy to tell the variants apart.
- instanceofNarrows the type to a class by checking whether the object was created by it.
- Type guards (value is T)Custom checking functions that narrow the type at the call site.
Spotted a mistake or missing an example? Write to us.