TypeScript-first Result type with literal error inference
A TypeScript-first wrapper around neverthrow that adds literal type inference and error composition patterns.
neverthrow is excellent for Result-based error handling, but creating typed errors requires boilerplate:
``typescript
// With plain neverthrow
import { err } from 'neverthrow'
// You need as const or explicit types to preserve the literal`
const result = err({ type: 'not_found' as const, message: 'User not found' })
This library fixes that with TypeScript 5.0+ const type parameters:
`typescript
// With @wentools/result
import { err } from '@wentools/result'
// Literal type is inferred automatically
const result = err('not_found', 'User not found')
// Type: Err
`
It also provides utilities for:
- Defining error types concisely
- Extracting and composing error types from functions
- Runtime Result detection without importing neverthrow types
`bashJSR (recommended)
npx jsr add @wentools/result
Usage
$3
`typescript
import { err, ok, type Result, type ErrorType } from '@wentools/result'// Define error types concisely
type UserNotFoundError = ErrorType<'user_not_found'>
type InvalidEmailError = ErrorType<'invalid_email', { email: string }>
// Create Results with inferred literal types
const getUser = (id: string): Result => {
const user = users.get(id)
if (!user) {
return err('user_not_found',
User ${id} not found)
}
return ok(user)
}// Add context to errors
const validateEmail = (email: string): Result => {
if (!email.includes('@')) {
return err('invalid_email', 'Email must contain @', { email })
}
return ok(email)
}
`$3
`typescript
import { errAsync, okAsync, type ResultAsync } from '@wentools/result'const createUser = (data: UserData): ResultAsync => {
return validateEmail(data.email)
.asyncAndThen((email) =>
checkEmailUnique(email)
.andThen(() => insertUser({ ...data, email }))
)
}
`$3
`typescript
import { type ExtractFnError } from '@wentools/result'// Extract and combine error types from multiple functions
type ServiceError =
| ExtractFnError
| ExtractFnError
| ExtractFnError
`$3
`typescript
import { isResult } from '@wentools/result'const handle = (value: unknown) => {
if (isResult(value)) {
if (value.isErr()) {
console.error(value.error)
}
}
}
`API
$3
| Function | Description |
|----------|-------------|
|
err(type, message, additional?) | Create an Err with literal type inference |
| errAsync(type, message, additional?) | Async version of err |
| ok(value) | Create an Ok (re-export from neverthrow) |
| okAsync(value) | Create an async Ok (re-export from neverthrow) |
| makeErr(type, message, additional?) | Create error object without wrapping in Err |
| rawErr(error) | Direct neverthrow err() for lifting unstructured errors |
| isResult(value) | Runtime check if value is a Result |
| propagateErr(result) | Propagate error to different Result type |$3
| Type | Description |
|------|-------------|
|
Result | Sync Result (from neverthrow) |
| ResultAsync | Async Result (from neverthrow) |
| ErrorType | Utility for defining { type, message, ...additional } |
| ExtractError | Extract error type from Result or Promise |
| ExtractFnError | Extract error type from function return type |
| ExtractErrors | Union of errors from multiple Results |
| ExtractFnsError- TypeScript 5.0+ (for const type parameters)
- neverthrow 8.x (peer dependency)
MIT