CodePark/ questions / Unions & narrowing
START PRACTICINGPRACTICE
Frontend question · TypeScript › Unions & narrowing

What happens when this code is compiled?

function isString(v: unknown): boolean {
  return typeof v === "string";
}

function shout(v: string | number) {
  if (isString(v)) {
    return v.toUpperCase();
  }
  return v.toFixed(1);
}
Both toUpperCase and toFixed error, because a boolean return type does not narrow v

Both calls error. The function is annotated to return boolean, and a plain boolean gives the caller no type information. So v stays string | number in both branches. toUpperCase does not exist on number, and toFixed does not exist on string.

The option "It compiles, because
isString checks typeof internally" is wrong. TypeScript does not look inside the function body for this. To fix it, annotate the return type as v is string, which is a type predicate.

Since TypeScript 5.5, TypeScript can infer a predicate for an unannotated function like this. But the explicit
boolean annotation stops that from happening.