TypeScript by Example

Narrowing

Control-flow analysis with typeof, instanceof, in, equality, truthiness, and assignment narrowing.

TypeScript tracks a value's type through control flow. After a check, the value is narrower inside that branch.

typeof, instanceof, in, and equality checks narrow common unions.

function formatValue(value: string | number | Date): string {
  if (typeof value === "string") {
    return value.toUpperCase();
  }
  if (value instanceof Date) {
    return value.toISOString();
  }
  return value.toFixed(2);
}
 
type Shape = { radius: number } | { width: number; height: number };
 
function describe(shape: Shape): string {
  if ("radius" in shape) return `circle r=${shape.radius}`;
  return `rect ${shape.width}x${shape.height}`;
}

Truthiness removes known falsy values, but it does not create a special non-empty string type.

function greet(name: string | null): string {
  if (name == null) {
    return "Hello, stranger";
  }
  return `Hello, ${name}`;
}
 
type Profile = { avatar: string | undefined };
 
function renderAvatar(profile: Profile): string {
  const { avatar } = profile;
  if (!avatar) return "/default-avatar.png";
  return avatar;
}

In production

Prefer unknown at trust boundaries because it forces narrowing before use. Use explicit null checks for nullable data; truthiness checks are convenient, but they also treat "", 0, and false as absent.

Enjoyed this? Get more software craft delivered to your inbox.