~/ozaco
@ozaco/std
// std.result@ozaco/std/result
  1. docs
  2. std
  3. result

@ozaco/std

import from

@ozaco/std/result

Result

Two values instead of an exception. A Result<T, E> is either a success carrying a value or a failure carrying an error, a message and a trail of causes — so what can go wrong is part of the type, and the caller narrows it rather than guessing.

Building the two sides

succeed wraps a value. fail takes the error, an optional message, and any number of causes: the breadcrumbs that say where it came from.

const ok = succeed(42)
const bad = fail('E_NOT_FOUND', 'no row with that id', 'users.findById')

// from examples/std/result.test.ts

The error is whatever you want it to be — a string code, an Error, a tagged object. Only the shape around it is fixed.

Narrowing

isSuccess and isFailure are type guards, so a check narrows the union for the rest of the block. isResult answers whether a value is one at all, which matters at the edges where something arrives untyped.

if (isResult(value) && isSuccess(value)) {
  // value is Result.Success<unknown> here
}

// from examples/std/result.test.ts

Taking the value out

unwrap reads the success. Given a second argument it uses that instead when the result failed; given none, a failure is raised — it is the failure itself that comes out, not a wrapper.

const rows = unwrap(succeed([1, 2, 3]))
const missing = unwrap(fail('E_EMPTY'), [])

// from examples/std/result.test.ts

  • ›unwrap(result) on a failure throws. Reach for the default form, or narrow first.
  • ›unwrap also accepts a promise of a result and gives you a promise back.

Lifting

auto meets a value wherever it is: a plain value becomes a success, an existing result passes through unchanged, and a second argument is the fallback for a failure.

const lifted = auto(7)
const passed = auto(succeed(7))
const defaulted = auto(fail('E_GONE'), 0)

// from examples/std/result.test.ts

Catching what throws

throwable runs a callback and settles the outcome instead of letting it escape — the same for a synchronous throw and a rejected promise.

const parsed = throwable(() => JSON.parse('{ not json') as unknown)

// from examples/std/result.test.ts

Causes

A failure carries a causes array. asFailure turns a caught error into one, and appendCauses adds to the trail as the failure travels up, so the final value says how it got there.

const low = asFailure(new Error('ECONNREFUSED'), 'pool.acquire')
const high = appendCauses(low, 'users.findById')

// from examples/std/result.test.ts

Maybe

The optional half of the module: just holds a value, nothing holds none, and isJust / isNothing narrow between them. It is for absence, where Result is for failure.

const found = just('ada')
const absent = nothing<string>()

// from examples/std/result.test.ts

Result
~/ozaco

Runtime-agnostic TypeScript packages, published to npm.