/** * Transform the value if not an error. * If the value is an error, returns it unchanged. * * @example * const result = map(user, u => u.name) * // If user is User, result is string * // If user is NotFoundError, result is NotFoundError */ export function map( value: V, fn: (v: Exclude) => U, ): Extract | U { if (value instanceof Error) { return value as Extract } return fn(value as Exclude) } /** * Transform the error if it is an error. * If the value is not an error, returns it unchanged. * * @example * const result = mapError(fetchResult, e => new AppError({ cause: e })) * // Converts any error type to AppError */ export function mapError( value: V, fn: (e: Extract) => E2, ): E2 | Exclude { if (value instanceof Error) { return fn(value as Extract) } return value as Exclude } /** * Chain another errore-returning function. * If the value is an error, returns it unchanged. * If successful, runs fn and returns its result. * * @example * const result = andThen(userId, id => fetchUser(id)) * // If userId is ValidationError, result is ValidationError * // If userId is string, result is whatever fetchUser returns */ export function andThen( value: V, fn: (v: Exclude) => R, ): Extract | R { if (value instanceof Error) { return value as Extract } return fn(value as Exclude) } /** * Async version of andThen. * * @example * const result = await andThenAsync(userId, async id => { * const user = await fetchUser(id) * return user * }) */ export async function andThenAsync( value: V, fn: (v: Exclude) => Promise, ): Promise | R> { if (value instanceof Error) { return value as Extract } return fn(value as Exclude) } /** * Run a side effect if the value is not an error. * Returns the original value unchanged. * * @example * const result = tap(user, u => console.log('Got user:', u.name)) */ export function tap(value: V, fn: (v: Exclude) => void): V { if (!(value instanceof Error)) { fn(value as Exclude) } return value } /** * Async version of tap. * * @example * const result = await tapAsync(user, async u => { * await logToService(u) * }) */ export async function tapAsync( value: V, fn: (v: Exclude) => Promise, ): Promise { if (!(value instanceof Error)) { await fn(value as Exclude) } return value }