https://www.typescriptlang.org/docs/handbook/advanced-types.html

Type Guards and Differentiating Types

Union types are useful for modeling situations when values can overlap in the types can take on. What happens when we need to know specifically whether we have a Fish ? A common idiom in JavaScript to differentiate between two possible values is to check for the presence of a member. As we mentioned, you can only access members that are guaranteed to be in all the constituents of a union type.

[*// Try it out on TypeScript Playground*](<https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgELCgE2QbwFDKHIwA2AngBQCUAXMgG4D2wmA3AUSXGQKIDmfAM7U6TFuwC+ePKEixEKAGLBBAC1wdCggO7AAtiIbM2m5F14DhtI+LxS8mCAi5QUMAK4gEYYIxDI+CDAAZT04EhIABSDDZTVkAB80DBM8BD9BMGQAByDkAF4AoNDwqJiqdjxcsAA6c34hakrgGAocoLruBsFkKg0iZHSQQUYSCDrGPjaARl7JaWrOi0aKhY6dfSbpFraAcg29XeRQdqy+-AHFg637HdOa0jJe-qJFx5vpIcziFVVorMK1WQcB6cVUlRgv3+NWuqxkrR+amhB2eFyIkKR610BlWEiAA>)

interface Bird {
    fly(): void;
    layEggs(): void;
}

interface Fish {
    swim(): void;
    layEggs(): void;
}

declare function getSmallPet(): Fish | Bird;

const pet = getSmallPet();

pet.layEggs();

// This condition will always return true since the function is always defined. Did you mean to call it instead?(2774)
if( pet.layEggs ) {
    console.log( 1 );
}

pet.layEggs();

// Property 'swim' does not exist on type 'Bird | Fish'.
//   Property 'swim' does not exist on type 'Bird'.(2339)
pet.swim();

if( 'swim' in pet ) {
    pet.swim();
}

// Property 'fly' does not exist on type 'Bird | Fish'.
//   Property 'fly' does not exist on type 'Fish'.(2339)
if( pet.fly ) {

		// Property 'fly' does not exist on type 'Bird | Fish'.
		//   Property 'fly' does not exist on type 'Fish'.(2339)
    pet.fly();
}

const fishPet = pet as Fish;

fishPet.swim();

if( fishPet.swim ) {
		fishPet.swim();
}

User-Defined Type Guards

It just so happens that TypeScript has something called a type guard . A type guard is some expression that performs a runtime check that guarantees the type in some scope.

Using type predicates

function isFish( pet: Fish | Bird ): pet is Fish {
		return ( pet as Fish ).swim !== undefined;
}
export default ( x: unknown ): x is Error => ( {} ).toString.call( x ) === '[object Error]';

Using the in operator

if( 'swim' in pet ) {
		return pet.swim)(;
}

typeof type guards

if( typeof x === 'number' ) {
		x.slice( 1 );
}

instanceof type guards

if( pet instanceof Birt ) {
		pet.fly();
}

The right side of the instanceof needs to be a constructor function, and TypeScript will narrow down to:

  1. the type of the function's prototype property if its type is not any .
  2. the union of types returned by that type's construct signatures.

in that order.