TypeScript: explicit errors with a Result type

Exceptions can be thrown from anywhere and are invisible in a function's type, so callers easily forget to handle them. A Result type makes failure part of the signature. It is a discriminated union: either an ok result carrying a value, or a failed result carrying an error. The ok field is the discriminant.

TypeScript
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };

function parseAge(text: string): Result<number, string> {
  const n = Number(text);
  if (text.trim() === "" || Number.isNaN(n)) {
    return { ok: false, error: "not a number" };
  }
  if (!Number.isInteger(n) || n < 0 || n > 150) {
    return { ok: false, error: "out of range" };
  }
  return { ok: true, value: n };
}

for (const input of ["42", "abc", "200", ""]) {
  const result = parseAge(input);
  if (result.ok) {
    console.log("age " + result.value);
  } else {
    console.log("error: " + result.error);
  }
}
Read the full lesson