@wentools/result
v0.1.3
Published
TypeScript-first Result type with literal error inference
Maintainers
Readme
@wentools/result
A TypeScript-first wrapper around neverthrow that adds literal type inference and error composition patterns.
Why This Exists
neverthrow is excellent for Result-based error handling, but creating typed errors requires boilerplate:
// 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:
// With @wentools/result
import { err } from '@wentools/result'
// Literal type is inferred automatically
const result = err('not_found', 'User not found')
// Type: Err<never, { type: 'not_found'; message: string }>It also provides utilities for:
- Defining error types concisely
- Extracting and composing error types from functions
- Runtime Result detection without importing neverthrow types
Install
# JSR (recommended)
npx jsr add @wentools/result
# Deno
deno add jsr:@wentools/resultUsage
Basic Error Creation
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<User, UserNotFoundError> => {
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<string, InvalidEmailError> => {
if (!email.includes('@')) {
return err('invalid_email', 'Email must contain @', { email })
}
return ok(email)
}Async Chains
import { errAsync, okAsync, type ResultAsync } from '@wentools/result'
const createUser = (data: UserData): ResultAsync<User, CreateError> => {
return validateEmail(data.email)
.asyncAndThen((email) =>
checkEmailUnique(email)
.andThen(() => insertUser({ ...data, email }))
)
}Error Type Composition
import { type ExtractFnError } from '@wentools/result'
// Extract and combine error types from multiple functions
type ServiceError =
| ExtractFnError<typeof getUser>
| ExtractFnError<typeof validateEmail>
| ExtractFnError<typeof createUser>Runtime Type Check
import { isResult } from '@wentools/result'
const handle = (value: unknown) => {
if (isResult(value)) {
if (value.isErr()) {
console.error(value.error)
}
}
}API
Functions
| 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 |
Types
| Type | Description |
|------|-------------|
| Result<T, E> | Sync Result (from neverthrow) |
| ResultAsync<T, E> | Async Result (from neverthrow) |
| ErrorType<Type, Additional?> | Utility for defining { type, message, ...additional } |
| ExtractError<T> | Extract error type from Result or Promise |
| ExtractFnError<F> | Extract error type from function return type |
| ExtractErrors<T[]> | Union of errors from multiple Results |
| ExtractFnsError<F[]> | Union of errors from multiple functions |
Requirements
- TypeScript 5.0+ (for const type parameters)
- neverthrow 8.x (peer dependency)
License
MIT
