result
import {ok, err, wrap, defineError} from 'mikrojs/result'
import type {Result, OkResult, ErrResult} from 'mikrojs/result'The Result type is how Mikro.js represents operations that can fail. Instead of throwing exceptions, functions return Result<T, E> where T is the success value and E is a typed error.
See the Error Handling guide for a full introduction.
Functions
ok()
Creates a successful result.
function ok(): OkResult<void>
function ok<T>(value: T): OkResult<T>const result = ok(42)
result.ok // true
result.value // 42err()
Creates a failed result.
function err<E>(error: E): ErrResult<E>const result = err({name: 'NotFound'})
result.ok // false
result.error // {name: 'NotFound'}wrap()
Wraps a throwing function in a Result. If the function returns normally, you get Ok. If it throws, you get Err with the caught Error.
function wrap<T>(fn: () => T): Result<T, Error>import {wrap} from 'mikrojs/result'
const parsed = wrap(() => JSON.parse(untrustedInput))
if (!parsed.ok) {
console.error('Bad JSON:', parsed.error.message)
return
}
parsed.value // the parsed objectUseful as a bridge between throwing built-ins (JSON.parse, decodeURIComponent, etc.) and the result-based error handling used by mikrojs/* modules.
defineError()
Defines a set of named error variants. Each variant is a factory function that produces a tagged error object.
function defineError<D>(name: string, variants: D): ErrorConstructors<D>const SensorError = defineError('SensorError', {
ReadFailed: (message: string) => ({message}),
NotConnected: () => ({}),
})
const e = SensorError.ReadFailed('timeout')
// {name: 'ReadFailed', message: 'timeout'}Result methods
Both OkResult and ErrResult share the same method interface. The behavior depends on whether the result is Ok or Err.
.ok
true for success, false for failure. Use this to narrow the type:
const result = pinMode(20, 'OUTPUT')
if (!result.ok) {
console.error(result.error.name)
return
}
// result.value is available here.value / .error
OkResulthas.value: Tand no.errorErrResulthas.error: Eand no.value
.isOk() / .isErr()
Type guard methods. Equivalent to checking .ok directly.
.map(fn)
Transforms the success value, leaving errors untouched.
const doubled = ok(21).map((v) => v * 2) // OkResult<number>, value: 42
const failed = err('oops').map((v) => v * 2) // ErrResult<string>, unchanged.mapErr(fn)
Transforms the error value, leaving successes untouched.
const result = err('oops').mapErr((e) => ({message: e}))
// ErrResult<{message: string}>.andThen(fn)
Chains a function that itself returns a Result. Useful for sequencing operations that can each fail.
const result = ok(20)
.andThen((pin) => pinMode(pin, 'OUTPUT'))
.andThen(() => ok('ready')).match(handlers)
Exhaustive pattern matching on the result.
const message = result.match({
ok: (value) => `Got: ${value}`,
err: (error) => `Failed: ${error.name}`,
}).orPanic(message)
Returns the value if Ok, or crashes the program with the given message if Err. The error is included as the cause.
const value = pinMode(20, 'OUTPUT').orPanic('Failed to set pin mode')Use this when failure is truly unrecoverable (e.g., during setup).
Types
Result<T, E>
type Result<T, E> = OkResult<T> | ErrResult<E>ErrorOf<T>
Utility type that extracts the union of error shapes from an error constructor object (returned by defineError).
type MyError = ErrorOf<typeof SensorError>
// {name: 'ReadFailed'; message: string} | {name: 'NotConnected'}