Lightweight Result type for TypeScript - API contract for BE ↔ FE
npm install ts-micro-result> Lightweight Result type for TypeScript
>
> API contract for BE ↔ FE. Not a FP monad.



!Edge Ready
!JSON First
!No Exceptions
!API Contract
ts-micro-result is a JSON-safe Result type for API boundaries.
- Designed for BE ↔ FE contracts
- Works great with Edge / Serverless
- No classes, no exceptions, no FP chains
- Errors are data, not thrown
``ts
import { ok, err } from 'ts-micro-result'
import type { Result } from 'ts-micro-result'
// Backend returns Result
function getUser(id: string): Result
if (!user) return err({ code: 'NOT_FOUND', message: 'User not found' })
return ok(user)
}
// Frontend receives predictable JSON
const res = await fetch('/api/users/123')
const result = await res.json() // { ok: true, data: {...} } or { ok: false, errors: [...] }
`
---
Use ts-micro-result if:
- You design APIs with explicit error contracts
- You want predictable BE ↔ FE JSON responses
- You run on Edge / Serverless (Cloudflare, Vercel, Workers)
- You need errors as data (loggable, cacheable, replayable)
Do NOT use if:
- You want map/flatMap/unwrap → use neverthrow
- You prefer throwing exceptions → use try/catch
- You need internal-only error handling → use custom patterns
---
`bash`
npm install ts-micro-result
`ts
import { ok, err } from 'ts-micro-result'
import type { Result } from 'ts-micro-result'
function getUser(id: string): Result
const user = db.find(id)
if (!user) {
return err({ code: 'NOT_FOUND', message: 'User not found' })
}
return ok(user)
}
const result = getUser('123')
if (result.ok) {
console.log(result.data.name) // TypeScript knows data is User
} else {
console.log(result.errors[0].message)
}
`
| Entry | Use Case | Size |
|-------|----------|------|
| ts-micro-result | Full API | ~2.5 kB |ts-micro-result/lite
| | Edge Workers, ultra-small bundles | < 1 kB |ts-micro-result/http
| | HTTP helpers | ~0.5 kB |ts-micro-result/types
| | FE import type only | 0 kB |
`ts`
ok() // Result
ok(data) // Result
ok(data, meta) // Result
okJson(data) // Result
err(error) // Err
err([error1, error2]) // Err with multiple errors
okPage(items, pagination) // Result
> Note: ok() accepts any type - JSON-safety is by convention.okJson()
> Use if you want compile-time enforcement that data extends JsonValue.
ok() vs ok(null):
- ok() → void operations (DELETE, UPDATE) → Resultok(null)
- → null is valid data → Result
`ts`
match(result, { ok, err }) // Pattern matching
isResult(value) // Runtime type guard
isOk(result) / isErr(result) // Type guards
combine([r1, r2, r3]) // Combine Results into array
combineObject({ a: r1 }) // Combine Results into object
serialize(result) // Deep JSON-safety
`ts
toHttpResponse(result) // ok(data) → 200, ok() → 204, err() → 400
sendResponse(res, response) // Express/Fastify helper
created(result) // 201
accepted(result) // 202
// Adapter for automatic error-to-status mapping
const toHttp = withFallbackStatus(createHttpResultAdapter(errorMap), 400)
`
| Result | Status | Body |
|--------|--------|------|
| ok(data) | 200 | JSON |ok()
| | 204 | null |err()
| | 400 | JSON |
`ts
type Result
interface Ok
readonly ok: true
readonly data: T
readonly meta?: ResultMeta
}
interface Err {
readonly ok: false
readonly errors: readonly ErrorDetail[]
readonly meta?: ResultMeta
}
interface ErrorDetail {
readonly code: string // Machine-readable
readonly message: string // Human-readable
readonly field?: string // For validation
}
interface ResultMeta {
readonly pagination?: Pagination
readonly traceId?: string
readonly params?: Record
}
`
params is opaque metadata passed through the Result.
The library never interprets or mutates it.
Use it for domain-specific data that doesn't fit standard fields:
`ts
// Rate limiting
return err(
{ code: 'RATE_LIMIT_EXCEEDED', message: 'Too many requests' },
{
traceId,
params: {
retryAfter: 60,
timestamp: Date.now(),
limit: 'user_login',
},
}
)
// Cache hints
return ok(user, {
params: { cacheKey: user:${user.id}, ttl: 3600 },`
})
✔ Typed
✔ Keeps message clean
✔ Doesn't leak HTTP concerns
✔ Doesn't break Result shape
- docs/http.md — HTTP integration, adapters, policy wrappers
- docs/examples.md — React Query, SWR, Express, Hono, pagination, error factories
- docs/MIGRATION.md — v2 → v3 migration guide
- docs/CHANGELOG.md — Version history
| Library | Purpose |
|---------|---------|
| ts-micro-result | API boundaries, Edge/Serverless, JSON contracts |
| neverthrow | Internal logic, FP patterns, map/flatMap |err()`) |
| fp-ts | Pure FP, effect systems |
| Zod / Valibot | Input validation |
| RFC 7807 | HTTP-level error format (can use inside
MIT