Narrowing uncertain values
Narrow with in and instanceof
Use property checks for object unions and constructor checks for real runtime classes.
typeof only distinguishes primitives. Every object answers 'object', so a union of two object shapes needs a different runtime question. You have two: does this property exist, and was this built by that constructor?
Narrow with in
The JavaScript in operator checks whether a property exists on an object or its prototype chain. TypeScript can use that fact to narrow an object union:
type Success = { data: string }
type Failure = { message: string }
function print(result: Success | Failure) {
if ('message' in result) {
console.error(result.message)
return
}
console.log(result.data)
}
Inside the if, only Failure has a message property, so result is a Failure. After the early return, TypeScript knows the remaining code deals with Success, and result.data compiles.
Without the check, result.data fails:
Property 'data' does not exist on type 'Success | Failure'.
Property 'data' does not exist on type 'Failure'.
One caveat: optional properties can appear in both branches because they may exist or be absent. If both variants declare message?: string, the in check proves nothing. A required discriminant is clearer when variants overlap.
Narrow with instanceof
instanceof checks the prototype chain:
function logWhen(value: Date | string) {
if (value instanceof Date) {
console.log(value.toISOString())
} else {
console.log(value)
}
}
In the first branch value is a Date, so toISOString() is available. In the else branch it must be a string.
This works for runtime constructors such as Date, Error, URL, and your JavaScript classes. It cannot use a type alias or interface because those disappear during compilation. Writing value instanceof Success fails with:
'Success' only refers to a type, but is being used as a value here.
That error is the compiler reminding you which check you need. When the variants are plain object shapes, reach for in or a discriminant field. When they are class instances, instanceof is the direct, honest check.
Exercise: create a union of Date | string, narrow it with instanceof, and format both branches.
Lesson completed