typescript 43 lines · 8 steps

A Result type for typed error handling

A discriminated union that models success or failure as a value, with combinators to transform it without throwing.

Explained by highlit
1type Ok<T> = { ok: true; value: T };
2type Err<E> = { ok: false; error: E };
3export type Result<T, E> = Ok<T> | Err<E>;
4 
5export const ok = <T>(value: T): Ok<T> => ({ ok: true, value });
6export const err = <E>(error: E): Err<E> => ({ ok: false, error });
7 
8export function isOk<T, E>(result: Result<T, E>): result is Ok<T> {
9 return result.ok;
10}
11 
12export function map<T, U, E>(
13 result: Result<T, E>,
14 fn: (value: T) => U,
15): Result<U, E> {
16 return result.ok ? ok(fn(result.value)) : result;
17}
18 
19export function andThen<T, U, E>(
20 result: Result<T, E>,
21 fn: (value: T) => Result<U, E>,
22): Result<U, E> {
23 return result.ok ? fn(result.value) : result;
24}
25 
26export function mapErr<T, E, F>(
27 result: Result<T, E>,
28 fn: (error: E) => F,
29): Result<T, F> {
30 return result.ok ? result : err(fn(result.error));
31}
32 
33export function unwrapOr<T, E>(result: Result<T, E>, fallback: T): T {
34 return result.ok ? result.value : fallback;
35}
36 
37export function fromThrowable<T>(fn: () => T): Result<T, Error> {
38 try {
39 return ok(fn());
40 } catch (e) {
41 return err(e instanceof Error ? e : new Error(String(e)));
42 }
43}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Modeling failure as a value instead of an exception makes error paths explicit and type-checked.
  2. 2A shared boolean tag lets TypeScript narrow a union to exactly one variant after a truthiness check.
  3. 3Small combinators like map and andThen let you chain fallible steps while short-circuiting on the first error.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A Result type for typed error handling — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code