patterntypescriptModeratepending
Pattern: Error handling in functional pipelines
Viewed 0 times
ResultEitherfunctionalpipelinemapflatMap
Problem
Chaining operations that can fail requires nested try/catch blocks that obscure the happy path.
Solution
Use Result/Either types for composable error handling:
// TypeScript Result type:
type Result<T, E = Error> =
| { 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 };
}
function map<T, U, E>(result: Result<T, E>, fn: (v: T) => U): Result<U, E> {
return result.ok ? ok(fn(result.value)) : result;
}
function flatMap<T, U, E>(result: Result<T, E>, fn: (v: T) => Result<U, E>): Result<U, E> {
return result.ok ? fn(result.value) : result;
}
// Usage - composable pipeline:
function processOrder(input: unknown): Result<Order, string> {
return flatMap(
flatMap(
flatMap(
validateInput(input), // Result<ValidInput, string>
checkInventory // Result<InventoryOk, string>
),
chargePayment // Result<PaymentOk, string>
),
createOrder // Result<Order, string>
);
}
// With pipe helper:
const result = pipe(
validateInput(input),
flatMap(checkInventory),
flatMap(chargePayment),
flatMap(createOrder),
);
if (!result.ok) {
console.error(result.error); // Typed error
}
// TypeScript Result type:
type Result<T, E = Error> =
| { 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 };
}
function map<T, U, E>(result: Result<T, E>, fn: (v: T) => U): Result<U, E> {
return result.ok ? ok(fn(result.value)) : result;
}
function flatMap<T, U, E>(result: Result<T, E>, fn: (v: T) => Result<U, E>): Result<U, E> {
return result.ok ? fn(result.value) : result;
}
// Usage - composable pipeline:
function processOrder(input: unknown): Result<Order, string> {
return flatMap(
flatMap(
flatMap(
validateInput(input), // Result<ValidInput, string>
checkInventory // Result<InventoryOk, string>
),
chargePayment // Result<PaymentOk, string>
),
createOrder // Result<Order, string>
);
}
// With pipe helper:
const result = pipe(
validateInput(input),
flatMap(checkInventory),
flatMap(chargePayment),
flatMap(createOrder),
);
if (!result.ok) {
console.error(result.error); // Typed error
}
Why
Result types make errors values instead of exceptions. This enables composition, explicit error handling, and type-safe error propagation.
Revisions (0)
No revisions yet.