Error handling for asynchronous operations is often written with try-catch, but the location where exceptions occur and the location where they are handled tend to diverge. With the Result type pattern, you can explicitly separate success and failure as return values.
Prerequisite: Conversion to Error Type
A helper to reliably convert unknown type errors into Error type.
export function toError(error: unknown): Error { if (error instanceof Error) return error; return new Error(error as never);}Definition of Result Type
interface Failure { data: undefined; error: Error;}
interface Success<T> { data: T; error: undefined;}
type Result<T> = Success<T> | Failure;Example Implementation of fetch Wrapper
import { toError } from './toError.js'
export async function fetcher<T>( url: RequestInfo, init?: RequestInit): Promise<Result<T>> { const UNDEF = undefined;
// When fetch fails (network errors, etc.) const response = await fetch(url, init).catch(toError); if (response instanceof Error) { return { data: UNDEF, error: response }; }
// HTTP error responses if (!response.ok) { return { data: UNDEF, error: new Error(`HTTP ${response.status}: ${response.statusText}`) }; }
// Success const data = await response.json(); return { data, error: UNDEF };}Usage Example
const result = await fetcher<User>("/api/user/123");
if (result.error) { console.error("Failed to fetch:", result.error.message); return;}
// When result.error is undefined, TypeScript infers result.data as Tconsole.log(result.data.name);Benefits and Considerations
Benefits:
- Success and failure become clear from the return type
- Reduced try-catch blocks improve readability
- Error handling can be enforced (omission causes type errors)
Considerations:
- If the ECMAScript Safe Assignment Operator proposal is standardized, built-in similar functionality may become available
- Not as complete as Go or Rust’s language built-in Result types
- Detailed error handling such as validation errors requires separate implementation
The implementation is simple, but it’s effective when you want to handle errors type-safely in small-scale projects.
hsb.horse