//#region src/error.d.ts /** Any tagged error (for generic constraints) */ type AnyTaggedError = Error & { readonly _tag: string; }; /** * Factory for tagged error classes. * * @example * class NotFoundError extends TaggedError("NotFoundError")<{ * id: string; * message: string; * }>() {} * * const err = new NotFoundError({ id: "123", message: "Not found: 123" }); * err._tag // "NotFoundError" * err.id // "123" * err.message // "Not found: 123" * * // Check if any tagged error * TaggedError.is(err) // true */ declare const TaggedError: { (tag: Tag): = {}>() => TaggedErrorClass; /** Type guard for any TaggedError instance */ is(value: unknown): value is AnyTaggedError; }; /** Instance type produced by TaggedError factory */ type TaggedErrorInstance = Error & { readonly _tag: Tag; toJSON(): object; } & Readonly; /** Class type produced by TaggedError factory */ type TaggedErrorClass = { new (...args: keyof Props extends never ? [args?: {}] : [args: Props]): TaggedErrorInstance; /** Type guard for this error class */ is(value: unknown): value is TaggedErrorInstance; }; /** Handler map for exhaustive matching */ type MatchHandlers = { [K in E["_tag"]]: (err: Extract) => R }; /** Partial handler map for non-exhaustive matching */ type PartialMatchHandlers = Partial>; /** Extract handled tags from a handlers object */ type HandledTags = Extract; /** * Exhaustive pattern match on tagged error union. * * @example * // Data-first * matchError(err, { * NotFoundError: (e) => `Missing: ${e.id}`, * ValidationError: (e) => `Invalid: ${e.field}`, * }); * * // Data-last (pipeable) * pipe(err, matchError({ * NotFoundError: (e) => `Missing: ${e.id}`, * ValidationError: (e) => `Invalid: ${e.field}`, * })); */ declare const matchError: { (err: E, handlers: MatchHandlers): R; (handlers: MatchHandlers): (err: E) => R; }; /** * Partial pattern match with fallback for unhandled tags. * * @example * matchErrorPartial(err, { * NotFoundError: (e) => `Missing: ${e.id}`, * }, (e) => `Unknown: ${e.message}`); */ declare const matchErrorPartial: { >(err: E, handlers: H, fallback: (e: Exclude>; }>) => R): R; = PartialMatchHandlers>(handlers: H, fallback: (e: Exclude>; }>) => R): (err: E) => R; }; /** * Type guard for tagged error instances. * * @example * if (isTaggedError(value)) { value._tag } */ declare const isTaggedError: (value: unknown) => value is AnyTaggedError; declare const UnhandledException_base: TaggedErrorClass<"UnhandledException", { message: string; cause: unknown; }>; /** * Wraps exceptions caught by Result.try/tryPromise. * Custom constructor derives message from cause. */ declare class UnhandledException extends UnhandledException_base { constructor(args: { cause: unknown; }); } declare const Panic_base: TaggedErrorClass<"Panic", { message: string; cause?: unknown; }>; /** * Unrecoverable error — user code threw inside Result operations. * * @example * // Panic in generator cleanup: * Result.gen(function* () { * try { * yield* Result.err("expected error"); * } finally { * throw new Error("cleanup failed"); // Panic! * } * }); * * // Panic in combinator: * Result.ok(1).map(() => { throw new Error("oops"); }); // Panic! */ declare class Panic extends Panic_base {} declare const ResultDeserializationError_base: TaggedErrorClass<"ResultDeserializationError", { message: string; value: unknown; }>; /** * Returned when Result.deserialize receives invalid input. * * @example * const result = Result.deserialize(invalidData); * if (Result.isError(result) && ResultDeserializationError.is(result.error)) { * console.log("Invalid input:", result.error.value); * } */ declare class ResultDeserializationError extends ResultDeserializationError_base { constructor(args: { value: unknown; }); } /** * Type guard for Panic instances. * * @example * if (isPanic(value)) { value.cause } */ declare const isPanic: (value: unknown) => value is Panic; /** * Throw an unrecoverable Panic. * * @example * panic("something went wrong", cause); */ declare const panic: (message: string, cause?: unknown) => never; //#endregion //#region src/result.d.ts /** * Successful result variant. * * @template A Success value type. * @template E Error type (phantom - for type unification). * * @example * const result = new Ok(42); * result.value // 42 * result.status // "ok" */ declare class Ok { readonly value: A; readonly status: "ok"; constructor(value: A); /** Returns true, narrowing Result to Ok. */ isOk(): this is Ok; /** Returns false, narrowing Result to Err. */ isErr(): this is Err; /** * Transforms success value. * * @template B Transformed type. * @param fn Transformation function. * @returns Ok with transformed value. * @throws {Panic} If fn throws. * * @example * ok(2).map(x => x * 2) // Ok(4) */ map(fn: (a: A) => B): Ok; /** * No-op on Ok, returns self with new phantom error type. * * @template E2 New error type. * @param _fn Ignored. * @returns Self with updated phantom E type. */ mapError(_fn: (e: never) => E2): Ok; /** * Chains Result-returning function. * * @template B New success type. * @template E2 New error type. * @param fn Function returning Result. * @returns Result from fn. * @throws {Panic} If fn throws. * * @example * ok(2).andThen(x => x > 0 ? ok(x) : err("negative")) // Ok(2) */ andThen(fn: (a: A) => Result): Result; /** * Chains async Result-returning function. * * @template B New success type. * @template E2 New error type. * @param fn Async function returning Result. * @returns Promise of Result from fn. * @throws {Panic} If fn throws synchronously or rejects. * * @example * await ok(1).andThenAsync(async x => ok(await fetchData(x))) */ andThenAsync(fn: (a: A) => Promise>): Promise>; /** * Pattern matches on Result. * * @template T Return type. * @param handlers Ok and err handlers. * @returns Result of ok handler. * @throws {Panic} If handler throws. * * @example * ok(2).match({ ok: x => x * 2, err: () => 0 }) // 4 */ match(handlers: { ok: (a: A) => T; err: (e: never) => T; }): T; /** * Extracts value. * * @param _message Ignored. * @returns The value. * * @example * ok(42).unwrap() // 42 */ unwrap(_message?: string): A; /** * Returns value, ignoring fallback. * * @template B Fallback type. * @param _fallback Ignored. * @returns The value. * * @example * ok(42).unwrapOr(0) // 42 */ unwrapOr(_fallback: B): A; /** * Runs side effect, returns self. * * @param fn Side effect function. * @returns Self. * @throws {Panic} If fn throws. * * @example * ok(2).tap(console.log).map(x => x * 2) // logs 2, returns Ok(4) */ tap(fn: (a: A) => void): Ok; /** * Runs async side effect, returns self. * * @param fn Async side effect function. * @returns Promise of self. * @throws {Panic} If fn throws synchronously or rejects. * * @example * await ok(2).tapAsync(async x => await log(x)) */ tapAsync(fn: (a: A) => Promise): Promise>; /** * Makes Ok yieldable in Result.gen blocks. * Immediately returns the value without yielding. * Yield type Err matches Err's for proper union inference. */ [Symbol.iterator](): Generator, A, unknown>; } /** * Error result variant. * * @template T Success type (phantom - for type unification with Ok). * @template E Error value type. * * @example * const result = new Err("failed"); * result.error // "failed" * result.status // "error" */ declare class Err { readonly error: E; readonly status: "error"; constructor(error: E); /** Returns false, narrowing Result to Ok. */ isOk(): this is Ok; /** Returns true, narrowing Result to Err. */ isErr(): this is Err; /** * No-op on Err, returns self with new phantom T. * * @template U New phantom success type. * @param _fn Ignored. * @returns Self. */ map(_fn: (a: never) => U): Err; /** * Transforms error value. * * @template E2 Transformed error type. * @param fn Transformation function. * @returns Err with transformed error. * @throws {Panic} If fn throws. * * @example * err("fail").mapError(e => new Error(e)) // Err(Error("fail")) */ mapError(fn: (e: E) => E2): Err; /** * No-op on Err, returns self with widened error type. * * @template U New phantom success type. * @template E2 Additional error type. * @param _fn Ignored. * @returns Self. */ andThen(_fn: (a: never) => Result): Err; /** * No-op on Err, returns Promise of self with widened error type. * * @template U New phantom success type. * @template E2 Additional error type. * @param _fn Ignored. * @returns Promise of self. */ andThenAsync(_fn: (a: never) => Promise>): Promise>; /** * Pattern matches on Result. * * @template R Return type. * @param handlers Ok and err handlers. * @returns Result of err handler. * @throws {Panic} If handler throws. * * @example * err("fail").match({ ok: x => x, err: e => e.length }) // 4 */ match(handlers: { ok: (a: never) => R; err: (e: E) => R; }): R; /** * Throws error with optional message. * * @param message Error message. * @throws Always throws. * * @example * err("fail").unwrap() // throws Error * err("fail").unwrap("custom") // throws Error("custom") */ unwrap(message?: string): never; /** * Returns fallback value. * * @template U Fallback type. * @param fallback Fallback value. * @returns Fallback. * * @example * err("fail").unwrapOr(42) // 42 */ unwrapOr(fallback: U): T | U; /** * No-op on Err, returns self. * * @param _fn Ignored. * @returns Self. */ tap(_fn: (a: never) => void): Err; /** * No-op on Err, returns Promise of self. * * @param _fn Ignored. * @returns Promise of self. */ tapAsync(_fn: (a: never) => Promise): Promise>; /** * Makes Err yieldable in Result.gen blocks. * Yields Err for proper union inference across multiple yields. */ [Symbol.iterator](): Generator, never, unknown>; } /** * Discriminated union representing operation success or failure. * * Both Ok and Err carry phantom types for the "other" variant: * - Ok: T is value, E is phantom error type * - Err: T is phantom success type, E is error * * This symmetric structure enables proper type inference in generator-based composition. * * @template T Success value type. * @template E Error value type. * * @example * type ParseResult = Result; */ type Result = Ok | Err; /** * Extracts error type E from yield union in Result.gen. * Yields are always Err, so we match on that pattern. * Distributive conditional: InferYieldErr | Err> = A | B */ type InferYieldErr = Y extends Err ? E : never; /** * Infer the Ok value type from a Result. * Distributive: InferOk | Ok> = A | B */ type InferOk = R extends Ok ? T : never; /** * Infer the Err value type from a Result. * Distributive: InferErr | Err> = A | B */ type InferErr = R extends Err ? E : never; /** * Constraint for any union of Ok/Err types. * Used in Result.gen to accept flexible return types from generators. */ type AnyResult = Ok | Err; declare function ok(): Ok; declare function ok(value: A): Ok; type RetryConfig = { retry?: { times: number; delayMs: number; backoff: "linear" | "constant" | "exponential"; /** Predicate to determine if an error should trigger a retry. Defaults to always retry. */ shouldRetry?: (error: E) => boolean; }; }; declare function resultAwait(promise: Promise>): AsyncGenerator, T, unknown>; /** Shape of a serialized Ok over RPC. */ interface SerializedOk { status: "ok"; value: T; } /** Shape of a serialized Err over RPC. */ interface SerializedErr { status: "error"; error: E; } /** Shape of a serialized Result over RPC. */ type SerializedResult = SerializedOk | SerializedErr; /** * Utilities for creating and handling Result types. * * @example * const result = Result.try(() => JSON.parse(str)); * const value = result.map(x => x.id).unwrapOr("default"); */ declare const Result: { /** * Creates successful result. * * @example * Result.ok(42) // Ok * Result.ok() // Ok - for side-effectful operations */ readonly ok: typeof ok; /** * Type guard for Ok. * * @example * if (Result.isOk(result)) { result.value } */ readonly isOk: (result: Result) => result is Ok; /** * Creates error result. * * @example * Result.err("failed") // Err("failed") */ readonly err: (error: E) => Err; /** * Type guard for Err. * * @example * if (Result.isError(result)) { result.error } */ readonly isError: (result: Result) => result is Err; /** * Executes sync function, wraps result/error in Result. * * @example * Result.try(() => JSON.parse(str)) * Result.try({ try: () => parse(x), catch: e => new ParseError(e) }) */ readonly try: { (thunk: () => Awaited, config?: { retry?: { times: number; }; }): Result; (options: { try: () => Awaited; catch: (cause: unknown) => Awaited; }, config?: { retry?: { times: number; }; }): Result; }; /** * Executes async function, wraps result/error in Result with retry support. * * @example * // Basic retry * await Result.tryPromise(() => fetch(url), { * retry: { times: 3, delayMs: 100, backoff: "exponential" } * }) * * @example * // Retry only for specific error types (user-defined TaggedError classes) * await Result.tryPromise({ * try: () => fetch(url), * catch: e => e instanceof TypeError ? new RetryableError(e) : new FatalError(e) * }, { * retry: { * times: 3, * delayMs: 100, * backoff: "exponential", * shouldRetry: e => e._tag === "RetryableError" * } * }) * * @example * // Async retry decisions: enrich error in catch handler * await Result.tryPromise({ * try: () => callApi(url), * catch: async (e) => { * const limited = await redis.get(`ratelimit:${userId}`); * return new ApiError({ cause: e, rateLimited: !!limited }); * } * }, { * retry: { times: 3, delayMs: 100, backoff: "exponential", shouldRetry: e => !e.rateLimited } * }) */ readonly tryPromise: { (thunk: () => Promise, config?: RetryConfig): Promise>; (options: { try: () => Promise; catch: (cause: unknown) => E | Promise; }, config?: RetryConfig): Promise>; }; /** * Transforms success value, passes error through. * * @example * Result.map(ok(2), x => x * 2) // Ok(4) * Result.map(x => x * 2)(ok(2)) // Ok(4) */ readonly map: { (result: Result, fn: (a: A) => B): Result; (fn: (a: A) => B): (result: Result) => Result; }; /** * Transforms error value, passes success through. * * @example * Result.mapError(err("fail"), e => new Error(e)) // Err(Error("fail")) */ readonly mapError: { (result: Result, fn: (e: E) => E2): Result; (fn: (e: E) => E2): (result: Result) => Result; }; /** * Chains Result-returning function on success. * * @example * Result.andThen(ok(2), x => x > 0 ? ok(x) : err("neg")) // Ok(2) */ readonly andThen: { (result: Result, fn: (a: A) => Result): Result; (fn: (a: A) => Result): (result: Result) => Result; }; /** * Chains async Result-returning function on success. * * @example * await Result.andThenAsync(ok(1), async x => ok(await fetch(x))) */ readonly andThenAsync: { (result: Result, fn: (a: A) => Promise>): Promise>; (fn: (a: A) => Promise>): (result: Result) => Promise>; }; /** * Pattern matches on Result. * * @example * Result.match(ok(2), { ok: x => x * 2, err: () => 0 }) // 4 */ readonly match: { (result: Result, handlers: { ok: (a: A) => T; err: (e: E) => T; }): T; (handlers: { ok: (a: A) => T; err: (e: E) => T; }): (result: Result) => T; }; /** * Runs side effect on success value, returns original result. * * @example * Result.tap(ok(2), console.log) // logs 2, returns Ok(2) */ readonly tap: { (result: Result, fn: (a: A) => void): Result; (fn: (a: A) => void): (result: Result) => Result; }; /** * Runs async side effect on success value, returns original result. * * @example * await Result.tapAsync(ok(2), async x => await log(x)) */ readonly tapAsync: { (result: Result, fn: (a: A) => Promise): Promise>; (fn: (a: A) => Promise): (result: Result) => Promise>; }; /** * Extracts value or throws. * * @example * Result.unwrap(ok(42)) // 42 * Result.unwrap(err("fail")) // throws Error */ readonly unwrap: (result: Result, message?: string) => A; /** * Extracts value or returns fallback. * * @example * Result.unwrapOr(ok(42), 0) // 42 * Result.unwrapOr(err("fail"), 0) // 0 */ readonly unwrapOr: { (result: Result, fallback: B): A | B; (fallback: B): (result: Result) => A | B; }; /** * Generator-based composition for Result types. * Errors from yielded Results form a union; use mapError to normalize. * * @example * const result = Result.gen(function* () { * const a = yield* getA(); // Err: ErrorA * const b = yield* getB(a); // Err: ErrorB * return Result.ok({ a, b }); * }); * // Result<{a, b}, ErrorA | ErrorB> * * @example * // Normalize error types with mapError * const result = Result.gen(function* () { * const a = yield* getA(); * const b = yield* getB(a); * return Result.ok({ a, b }); * }).mapError(e => new UnifiedError(e._tag, e.message)); * // Result<{a, b}, UnifiedError> * * @example * // Async with Result.await * const result = await Result.gen(async function* () { * const a = yield* Result.await(fetchA()); * const b = yield* Result.await(fetchB(a)); * return Result.ok({ a, b }); * }); */ readonly gen: { , R extends AnyResult>(body: () => Generator): Result, InferYieldErr | InferErr>; , R extends AnyResult, This>(body: (this: This) => Generator, thisArg: This): Result, InferYieldErr | InferErr>; , R extends AnyResult>(body: () => AsyncGenerator): Promise, InferYieldErr | InferErr>>; , R extends AnyResult, This>(body: (this: This) => AsyncGenerator, thisArg: This): Promise, InferYieldErr | InferErr>>; }; /** * Wraps Promise to be yieldable in async Result.gen blocks. * * @example * yield* Result.await(fetchUser(id)) */ readonly await: typeof resultAwait; /** * Converts a Result to a plain object for serialization (e.g., RPC, server actions). * * @example * const serialized = Result.serialize(ok(42)); // { status: "ok", value: 42 } */ readonly serialize: (result: Result) => SerializedResult; /** * Rehydrates serialized Result from RPC back into Ok/Err instances. * Returns `Err` if the input is not a valid serialized Result. * * @example * // Valid serialized Result * const result = Result.deserialize(rpcResponse); * if (Result.isOk(result)) { * console.log(result.value); // User * } * * // Invalid input returns ResultDeserializationError * const invalid = Result.deserialize({ foo: "bar" }); * if (Result.isError(invalid) && ResultDeserializationError.is(invalid.error)) { * console.log("Bad input:", invalid.error.value); * } */ readonly deserialize: (value: unknown) => Result; /** * @deprecated Use `Result.deserialize` instead. Will be removed in 3.0. */ readonly hydrate: (value: unknown) => Result; /** * Splits array of Results into tuple of [okValues, errorValues]. * * @example * partition([ok(1), err("a"), ok(2)]) // [[1, 2], ["a"]] */ readonly partition: (results: readonly Result[]) => [T[], E[]]; /** * Flattens nested Result into single Result. * * @example * const nested = Result.ok(Result.ok(42)); * Result.flatten(nested) // Ok(42) */ readonly flatten: (result: Result, E2>) => Result; }; //#endregion export { Err, type InferErr, type InferOk, Ok, Panic, Result, ResultDeserializationError, type SerializedErr, type SerializedOk, type SerializedResult, TaggedError, type TaggedErrorClass, type TaggedErrorInstance, UnhandledException, isPanic, isTaggedError, matchError, matchErrorPartial, panic }; //# sourceMappingURL=index.d.mts.map