Narrowing Types

Unions will cause errors if all types don't have a property

Error

function padLeft(padding: number | string, input: string) {
  return " ".repeat(padding) + input;
}
/*
	Argument of type 'string | number' is not assignable to parameter of type 'number'.
  Type 'string' is not assignable to type 'number'.
*/

Correct

function padLeft(padding: number | string, input: string) {
  if (typeof padding === "number") {
    return " ".repeat(padding) + input;
  }
  return padding + input;
}

Guards

Typeof

TypeScript expects this to return a certain set of strings:

  • "string"

  • "number"

  • "bigint"

  • "boolean"

  • "symbol"

  • "undefined"

  • "object"

  • "function"

Boolean

function printAll(strs: string | string[] | null) {
  if (strs && typeof strs === "object") {
    for (const s of strs) {
      console.log(s);
    }
  } else if (typeof strs === "string") {
    console.log(strs);
  }
}

Coerced to false

  • 0

  • NaN

  • "" (the empty string)

  • 0n (the bigint version of zero)

  • null

  • undefined

instanceof

x instanceof Foo checks whether the prototype chain of x contains Foo.prototype

unction logValue(x: Date | string) {
  if (x instanceof Date) {
    console.log(x.toUTCString());
  } else {
    console.log(x.toUpperCase());
  }
}

Advanced Types => Type predicates

Way 1

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

Way 2

function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

// Both calls to 'swim' and 'fly' are now okay.
let pet = getSmallPet();
 
if (isFish(pet)) {
  pet.swim();
} else {
  pet.fly();
}

Last updated