Union dispatch
Select the correct object shape from a union before reading shape-specific fields.
TypeScript · Const
TypeScript recognizes JavaScript’s in property check as a type guard. It narrows union members based on whether the tested key is required, optional, or unlisted.
The in operator checks whether an object or its prototype chain has a property. TypeScript uses that runtime check to narrow a union: the true branch keeps members with an optional or required property, while the false branch keeps members with an optional or missing property.
propertyKey in object| Name | Type | Description |
|---|---|---|
propertyKey | string | number | symbol | The property key to test; it must be assignable to string | number | symbol. |
value | object | The value whose object or prototype chain is tested; it must be assignable to object. |
A boolean indicating whether the property exists on the object or anywhere on its prototype chain.
in performs a runtime property-presence test, including inherited properties.type Order =
| { email: string }
| { callerNumber: string };
function contact(order: Order): string {
if ("email" in order) {
return order.email;
}
return order.callerNumber;
}
console.log(contact({ email: "dev@example.com" }));The property check selects the union member whose shape contains the tested key, allowing the corresponding property to be used safely.
Select the correct object shape from a union before reading shape-specific fields.
Validate dynamic or unknown object data by checking for a key, then narrowing that property independently.
Distinguish structurally different request, event, or command variants without adding a separate tag field.
in narrow a discriminated union?It is a JavaScript property-existence check that TypeScript also treats as a type guard. For a union, the true branch retains members with the tested property, including optional properties.
Follow-up: What happens with an unknown value? The check first narrows it to an object-like type containing the tested key, represented as an intersection with Record<key, unknown>.
The false branch retains union members where the property is optional or not declared. Therefore, it is not equivalent to proving that no runtime property exists on the value.
Follow-up: Why can a prototype property affect the result? JavaScript's in operator examines the object and its prototype chain, not only own properties.
The left operand must be assignable to string | number | symbol, and the right operand must be assignable to object. These checks prevent invalid property-key and primitive checks.
Follow-up: How can an unknown input be handled safely? First establish that it is an object, then use in, and narrow the resulting property value separately.
Narrowingtype guardsunion typesRecordunknownoptional properties