Lesson 18 / 25
Option/Maybe and Result/Either
Explicit absence and explicit failure.
Values instead of null and exceptions
null and undefined can appear almost anywhere and are easy to forget; exceptions are invisible in a function's signature. FP makes both explicit in the type. Option (Haskell Maybe, Rust Option) is either Some(value) or None. Result (Haskell Either, Rust Result) is either Ok(value) or Err(error). Callers must handle both cases before using the value. In TypeScript, strictNullChecks already makes T | undefined a lightweight Option; for errors, a small Result union or a library such as fp-ts, Effect or neverthrow works. Keep exceptions for truly unexpected failures (bugs, out of memory), and Result for expected ones (validation, not found).
A minimal Result type
Parsing returns failure as a value.
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
const ok = <T>(value: T): Result<T, never> => ({ ok: true, value });
const err = <E>(error: E): Result<never, E> => ({ ok: false, error });
type AgeError = 'not-a-number' | 'out-of-range';
function parseAge(input: string): Result<number, AgeError> {
const n = Number(input);
if (!Number.isInteger(n)) return err('not-a-number');
if (n < 0 || n > 150) return err('out-of-range');
return ok(n);
}
const r = parseAge('42');
if (r.ok) {
console.log(r.value + 1); // narrowed: value is a number
} else {
console.log(`Invalid age: ${r.error}`);
}Haskell Maybe
In Haskell, lookup :: Eq a => a -> [(a, b)] -> Maybe b returns Nothing when a key is absent, so callers cannot forget the missing case.
Quick check: What is the main advantage of returning Result instead of throwing?
- The possibility of failure is visible in the type and callers must handle it
- Result values cannot contain errors
- Throwing is not allowed in TypeScript
- Result makes code run in parallel
Answer
The possibility of failure is visible in the type and callers must handle it — Errors become ordinary values.