← Back to TypeScript Course | Chapter 18: Error Handling | Lesson 4 of 5

Result Type Pattern

The Result type pattern represents success and failure as explicit values instead of relying only on thrown exceptions. A discriminated union makes it possible to safely handle both outcomes.

Defining a Result Type

A Result type typically contains either an ok result carrying a value or an error result carrying an error value — success and failure become explicit data instead of something only discoverable via a thrown exception.

Example: Defining a Result Type

typescript
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
const success: Result<number, string> = { ok: true, value: 42 };
console.log(success);

Handling Success and Failure

Check the ok property before accessing value or error — this is exactly the shape TypeScript needs to safely narrow a discriminated union, so the compiler will actually stop you from reading value on a failed Result.

Example: Handling Success and Failure

typescript
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
function divide(a: number, b: number): Result<number, string> {
  return b === 0 ? { ok: false, error: "Division by zero" } : { ok: true, value: a / b };
}
const result = divide(10, 2);
if (result.ok) console.log(result.value);
else console.log(result.error);

Result with Custom Errors

The error side of a Result can hold a custom error class or any other structured error type, letting you carry as much detail about a failure as you want without resorting to throwing.

Example: Result with Custom Errors

typescript
class ValidationError extends Error {}
type Result<T> = { ok: true; value: T } | { ok: false; error: ValidationError };
function parseAge(input: string): Result<number> {
  const n = Number(input);
  return isNaN(n) ? { ok: false, error: new ValidationError("bad age") } : { ok: true, value: n };
}
console.log(parseAge("25"));

Result Helper Functions

Small helper functions — ok(value) and err(error) — make Result values quick to construct and keep call sites readable instead of manually building the object literal every time.

Example: Result Helper Functions

typescript
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
function ok<T>(value: T): Result<T, never> { return { ok: true, value }; }
function err<E>(error: E): Result<never, E> { return { ok: false, error }; }
console.log(ok(5), err("failed"));

When to Use Result

Result shines when failures are expected, routine outcomes — a validation failure, a not-found lookup — and callers should be forced to handle them explicitly rather than being able to ignore a thrown exception.

Example: When to Use Result

typescript
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
function findUser(id: number): Result<string, string> {
  return id === 1 ? { ok: true, value: "Ravi" } : { ok: false, error: "not found" };
}
const result = findUser(2);
console.log(result.ok ? result.value : result.error);
🔒

Chapter Quiz — Complete all 5 topics to unlock

0/5 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.