typesafe-ts
Version:
TypeScript utilities for type-safe error handling and optional values
887 lines • 39.9 kB
TypeScript
/**
* Represents a Result that contains an error value.
* This interface is used for type narrowing after calling `is_error()`.
*/
interface ErrorResult<ErrorType extends Error> {
readonly error: ErrorType;
}
/**
* Represents a Result that contains a success value.
* This interface is used for type narrowing after calling `is_ok()`.
*/
interface OkResult<ResultType> {
readonly value: ResultType;
}
/**
* A monadic type that represents either a successful value or an error.
* Result provides a type-safe way to handle operations that may fail without throwing exceptions.
*
* @template ResultType - The type of the success value
* @template ErrorType - The type of the error (must extend Error)
*
* @example
* ```typescript
* import { result, type Result } from "./result.ts";
*
* function divide(a: number, b: number): Result<number, Error> {
* if (b === 0) {
* return result.error(new Error("Division by zero"));
* }
* return result.ok(a / b);
* }
*
* const success = divide(10, 2);
* if (success.is_ok()) {
* console.log("Result:", success.value); // Result: 5
* }
*
* const failure = divide(10, 0);
* if (failure.is_error()) {
* console.log("Error:", failure.error.message); // Error: Division by zero
* }
* ```
*/
/**
* Common methods available on all Result instances.
*/
interface IResult<ResultType, ErrorType extends Error> {
/**
* Returns the string tag for Object.prototype.toString calls.
* Always returns "Result" for Result instances.
*/
get [Symbol.toStringTag](): "Result";
/**
* Type predicate that checks if this Result contains an error.
* If true, TypeScript will narrow the type to include the `error` property.
*
* @returns True if this Result contains an error, false if it contains a value
*
* @example
* ```typescript
* const result = result.error(new Error("Something went wrong"));
* if (result.is_error()) {
* console.log(result.error.message); // TypeScript knows .error exists
* }
* ```
*/
is_error(): this is ErrorResult<ErrorType>;
/**
* Type predicate that checks if this Result contains a success value.
* If true, TypeScript will narrow the type to include the `value` property.
*
* @returns True if this Result contains a value, false if it contains an error
*
* @example
* ```typescript
* const result = result.ok("Hello, World!");
* if (result.is_ok()) {
* console.log(result.value); // TypeScript knows .value exists
* }
* ```
*/
is_ok(): this is OkResult<ResultType>;
/**
* Returns the contained value if Ok, otherwise returns the provided default value.
*
* @param value_if_error - The value to return if this Result contains an error
* @returns The contained value if Ok, otherwise the default value
*
* @example
* ```typescript
* const success = result.ok(42);
* console.log(success.value_or(0)); // 42
*
* const failure = result.error(new Error("Failed"));
* console.log(failure.value_or(0)); // 0
* ```
*/
value_or(value_if_error: ResultType): ResultType;
/**
* Returns the contained error if Error, otherwise returns the provided default error.
*
* @param error_if_ok - The error to return if this Result contains a value
* @returns The contained error if Error, otherwise the default error
*
* @example
* ```typescript
* const failure = result.error(new Error("Original error"));
* console.log(failure.error_or(new Error("Default"))); // Error: Original error
*
* const success = result.ok("value");
* console.log(success.error_or(new Error("Default"))); // Error: Default
* ```
*/
error_or(error_if_ok: ErrorType): ErrorType;
/**
* Transforms the contained value if Ok, otherwise returns the error unchanged.
* This is the functor map operation for Result.
*
* @template NewResultType - The type of the transformed value
* @param fn - Function to transform the value if Ok
* @returns A new Result with the transformed value if Ok, otherwise the original error
*
* @example
* ```typescript
* const success = result.ok(5);
* const doubled = success.map(x => x * 2);
* console.log(doubled.value_or(0)); // 10
*
* const failure = result.error(new Error("Failed"));
* const transformed = failure.map(x => x * 2); // fn is not called
* console.log(transformed.is_error()); // true
* ```
*/
map<NewResultType>(fn: (value: ResultType) => NewResultType): Result<NewResultType, ErrorType>;
/**
* Transforms the contained error if Error, otherwise returns the value unchanged.
* This allows for error transformation and chaining.
*
* @template NewErrorType - The type of the transformed error
* @param fn - Function to transform the error if Error
* @returns A new Result with the transformed error if Error, otherwise the original value
*
* @example
* ```typescript
* const failure = result.error(new Error("Original"));
* const wrapped = failure.map_error(err => new Error(`Wrapped: ${err.message}`));
* if (wrapped.is_error()) {
* console.log(wrapped.error.message); // "Wrapped: Original"
* }
*
* const success = result.ok("value");
* const unchanged = success.map_error(err => new Error("Won't be called"));
* console.log(unchanged.is_ok()); // true
* ```
*/
map_error<NewErrorType extends Error>(fn: (error: ErrorType) => NewErrorType): Result<ResultType, NewErrorType>;
/**
* @deprecated Use map_error instead. This method will be removed in the next major version release.
*/
map_err<NewErrorType extends Error>(fn: (error: ErrorType) => NewErrorType): Result<ResultType, NewErrorType>;
/**
* Pattern matches against the Result, executing the appropriate callback and returning its result.
* This is useful when you need to transform both Ok and Error cases into the same output type.
*
* @template OKMatchResultType - The return type of the on_ok callback
* @template ErrorMatchResultType - The return type of the on_error callback
* @param handlers - Object containing callback functions for Ok and Error cases
* @param handlers.on_ok - Function to execute if Result is Ok, receiving the value
* @param handlers.on_error - Function to execute if Result is Error, receiving the error
* @returns The result of the executed callback
*
* @example
* ```typescript
* const success = result.ok(42);
* const message = success.match({
* on_ok: (value) => `Value is ${value}`,
* on_error: (error) => `Error occurred: ${error.message}`,
* });
* console.log(message); // "Value is 42"
*
* const failure = result.error(new Error("Something went wrong"));
* const errorMessage = failure.match({
* on_ok: (value) => `Value is ${value}`,
* on_error: (error) => `Error occurred: ${error.message}`,
* });
* console.log(errorMessage); // "Error occurred: Something went wrong"
* ```
*/
match<OKMatchResultType, ErrorMatchResultType>({ on_ok, on_error, }: {
on_ok: (value: ResultType) => OKMatchResultType;
on_error: (error: ErrorType) => ErrorMatchResultType;
}): OKMatchResultType | ErrorMatchResultType;
/**
* Monadic bind operation. Chains another Result-returning operation if this Result is Ok.
* If this Result is Error, the function is not called and the error is propagated.
* This is also known as flatMap in some languages.
*
* @template NewResultType - The type of the value in the returned Result
* @param fn - Function that takes the Ok value and returns a new Result
* @returns The Result returned by fn if Ok, otherwise the original error
*
* @example
* ```typescript
* function parseNumber(str: string): Result<number, Error> {
* const num = Number(str);
* return isNaN(num) ? result.error(new Error("Not a number")) : result.ok(num);
* }
*
* function divide(a: number, b: number): Result<number, Error> {
* return b === 0 ? result.error(new Error("Division by zero")) : result.ok(a / b);
* }
*
* const computation = parseNumber("10")
* .and_then(num => divide(num, 2));
*
* if (computation.is_ok()) {
* console.log(computation.value); // 5
* }
* ```
*/
and_then<NewResultType, NewErrorType extends Error = ErrorType>(fn: (value: ResultType) => Result<NewResultType, NewErrorType>): Result<NewResultType, NewErrorType | ErrorType>;
/**
* Provides a fallback Result if this Result is Error.
* If this Result is Ok, the function is not called and the value is preserved.
* This allows for error recovery and alternative computation paths.
*
* @template NewErrorType - The type of error in the fallback Result
* @param fn - Function that takes the Error and returns a fallback Result
* @returns The fallback Result returned by fn if Error, otherwise the original Ok value
*
* @example
* ```typescript
* function tryPrimary(): Result<string, Error> {
* return result.error(new Error("Primary failed"));
* }
*
* function tryFallback(): Result<string, Error> {
* return result.ok("Fallback success");
* }
*
* const outcome = tryPrimary()
* .or_else(() => tryFallback());
*
* if (outcome.is_ok()) {
* console.log(outcome.value); // "Fallback success"
* }
* ```
*/
or_else<NewResultType = ResultType, NewErrorType extends Error = ErrorType>(fn: (error: ErrorType) => Result<NewResultType, NewErrorType>): Result<ResultType | NewResultType, NewErrorType>;
/**
* Returns a generator that yields the contained value if this Result is Ok.
* If this Result is Error, the generator yields nothing (completes immediately).
* This allows for easy iteration over successful values in for-of loops and other iterator contexts.
*
* @returns A generator that yields the value if Ok, otherwise yields nothing
*
* @example
* ```typescript
* const success = result.ok(42);
* for (const value of success) {
* console.log(value); // 42
* }
*
* const failure = result.error(new Error("Failed"));
* for (const value of failure) {
* console.log("This won't execute");
* }
*
* // Useful for collecting successful values from multiple results
* const results = [
* result.ok(1),
* result.error(new Error("Failed")),
* result.ok(3)
* ];
*
* const values = [];
* for (const res of results) {
* for (const value of res) {
* values.push(value);
* }
* }
* console.log(values); // [1, 3]
* ```
*/
[Symbol.iterator](): Generator<ResultType, void, unknown>;
}
/**
* @inlineType
* @interface
*/
type Result<ResultType, ErrorType extends Error> = IResult<ResultType, ErrorType> & (OkResult<ResultType> | ErrorResult<ErrorType>);
type NonPromiseValue<ValueType> = [ValueType] extends [PromiseLike<unknown>] ? "Error: Value provided to `result.ok_async()` must not be a Promise. Use `result.try_async()` to wrap asynchronous values." : ValueType;
/**
* Error type returned by retry operations when all attempts fail.
* Contains the original error message, retry count, and all accumulated errors from failed attempts.
*/
interface RetryError<ErrorType extends Error = Error> extends Error {
name: "Result Retry Error";
message: `Failed after ${number} attempts.`;
errors: ErrorType[];
}
/**
* Error type returned by try_async operations when an async function throws or rejects.
* Contains comprehensive debugging information about the failed operation.
*/
declare class TryAsyncError extends Error {
constructor(operation: string, originalError?: unknown);
/** The original error/value that was thrown or caused the rejection */
originalError: unknown;
/** Description of the operation that failed */
operation: string;
/** Timestamp when the error occurred (milliseconds since epoch) */
timestamp: number;
}
/**
* An awaitable wrapper for Result that enables immediate method chaining on async operations.
* AsyncResult implements PromiseLike and provides Result transformation methods like map, and_then, and or_else.
* The AsyncResult must be awaited to inspect the final result with `is_ok()` or `is_error()`.
*
* @template ResultType - The type of the ok value
* @template ErrorType - The type of the error (must extend Error)
*
* @example
* ```typescript
* // Chain operations and await the final result in one expression
* const finalResult = await result.try_async(() => fetchUser("123"))
* .map(user => user.name.toUpperCase())
* .and_then(name => name ? result.ok(name) : result.error(new Error("Empty name")))
* .or_else(() => result.ok("Unknown"));
* ```
*/
declare class AsyncResult<ResultType, ErrorType extends Error> implements PromiseLike<Result<ResultType, ErrorType>> {
private promise;
/**
* Creates a new AsyncResult from a Promise that resolves to a Result.
*
* While `result.try_async()` is the preferred way to create AsyncResult instances,
* the constructor is useful when you have an async function that already returns
* a `Promise<Result>`. Wrapping it with `new AsyncResult()` provides access to
* the chaining API without requiring `await` and without "coloring" your function
* as async. This is particularly beneficial in contexts where `await` isn't allowed,
* such as top-level code or in component logic of some frontend frameworks.
*
* @param promise - A Promise that resolves to a Result
*
* @example
* ```typescript
* // Async function that returns Promise<Result>
* async function fetchUserData(id: string): Promise<Result<User, Error>> {
* return result.try_async(() => fetch(`/api/users/${id}`))
* .then(response => response.json());
* }
*
* // Without AsyncResult constructor: requires await, makes function async
* async function processUserAsync(id: string): Promise<Result<string, Error>> {
* const userData = await fetchUserData(id);
* return userData.map(user => user.name.toUpperCase());
* }
*
* // With AsyncResult constructor: no await needed, function stays sync
* function processUserSync(id: string): AsyncResult<string, Error> {
* return new AsyncResult(fetchUserData(id))
* .map(user => user.name.toUpperCase());
* }
*
* // Both usage patterns work the same way:
* const result1 = await processUserAsync("123");
* const result2 = await processUserSync("123");
* ```
*/
constructor(promise: Promise<Result<ResultType, ErrorType>>);
/**
* PromiseLike implementation equivalent to Promise.then. Allows AsyncResult to be awaited.
*
* @template TResult1 - The type returned when the promise resolves
* @template TResult2 - The type returned when the promise rejects
* @param onfulfilled - Callback executed when the AsyncResult resolves to a Result
* @param onrejected - Callback executed when the AsyncResult rejects
* @returns A PromiseLike that resolves to the result of the executed callback
*/
then<TResult1 = Result<ResultType, ErrorType>, TResult2 = never>(onfulfilled?: ((value: Result<ResultType, ErrorType>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
get [Symbol.toStringTag](): "Result";
/**
* Returns the contained value if Ok, otherwise returns the provided default value.
*
* @param value_if_error - The value to return if the Result contains an error
* @returns A Promise resolving to the contained value or the default value
*/
value_or(value_if_error: ResultType): Promise<ResultType>;
/**
* Access the contained error if this result is an error. Otherwise returns the provided default error.
*
* @param error_if_ok - The error to return if the Result contains a value
* @returns A Promise resolving to the contained error or the default error
*/
error_or(error_if_ok: ErrorType): Promise<ErrorType>;
/**
* Transform the contained value if Ok, otherwise return the error unchanged.
*
* @template NewResultType - The type of the transformed value
* @param fn - Function to transform the value if Ok
* @returns A new AsyncResult with the transformed value if Ok, otherwise the original error
*/
map<NewResultType>(fn: (value: ResultType) => NewResultType): AsyncResult<NewResultType, ErrorType>;
/**
* Transform the contained error if Error, otherwise return the value unchanged.
*
* @template NewErrorType - The type of the transformed error
* @param fn - Function to transform the error if Error
* @returns A new AsyncResult with the transformed error if Error, otherwise the original value
*/
map_error<NewErrorType extends Error>(fn: (error: ErrorType) => NewErrorType): AsyncResult<ResultType, NewErrorType>;
/**
* @deprecated Use map_error instead. This method will be removed in the next major version release.
*/
map_err<NewErrorType extends Error>(fn: (error: ErrorType) => NewErrorType): AsyncResult<ResultType, NewErrorType>;
/**
* Pattern match against the Result, executing the appropriate callback and returning its result.
*
* @template OKMatchResultType - The return type of the on_ok callback
* @template ErrorMatchResultType - The return type of the on_error callback
* @param handlers - Object containing callback functions for Ok and Error cases
* @param handlers.on_ok - Function to execute if Result is Ok, receiving the value
* @param handlers.on_error - Function to execute if Result is Error, receiving the error
* @returns A Promise resolving to the result of the executed callback
*/
match<OKMatchResultType, ErrorMatchResultType>({ on_ok, on_error, }: {
on_ok: (value: ResultType) => OKMatchResultType;
on_error: (error: ErrorType) => ErrorMatchResultType;
}): Promise<OKMatchResultType | ErrorMatchResultType>;
/**
* Chain another Result-returning operation if this Result is Ok.
* If this Result is Error, the function is not called and the error is propagated.
*
* @template NewResultType - The type of the value in the returned Result
* @param fn - Function that takes the Ok value and returns a new Result
* @returns A new AsyncResult with the result returned by fn if Ok, otherwise the original error
*/
and_then<NewResultType = ResultType, NewErrorType extends Error = ErrorType>(fn: (value: ResultType) => Result<NewResultType, NewErrorType>): AsyncResult<NewResultType, ErrorType | NewErrorType>;
/**
* Provide a fallback Result if this Result is Error.
* If this Result is Ok, the function is not called and the value is preserved.
*
* @template NewErrorType - The type of error in the fallback Result
* @param fn - Function that takes the Error and returns a fallback Result
* @returns A new AsyncResult with the fallback Result returned by fn if Error, otherwise the original Ok value
*/
or_else<NewResultType = ResultType, NewErrorType extends Error = ErrorType>(fn: (error: ErrorType) => Result<NewResultType, NewErrorType>): AsyncResult<ResultType | NewResultType, NewErrorType>;
/**
* Executes an async function with the contained value if Ok, and wraps the result in a Result.
* If this AsyncResult is Error, the function is not called and the error is propagated.
* If the async function throws or rejects, the error is caught and wrapped in a TryAsyncError with detailed debugging information.
*
* @template NewResultType - The type of the value returned by the async function
* @param fn - Async function that takes the Ok value and returns a Promise
* @returns A new AsyncResult containing the result of the async function or a union of the original error and TryAsyncError
*
* @example
* ```typescript
* // Chain async operations with rich error information
* const userData = await result.try_async(() => fetch('/api/user/123'))
* .try_async(response => response.json()) // Creates TryAsyncError if JSON parsing fails
* .map(user => user.name)
* .match(
* name => console.log(`User: ${name}`),
* error => {
* if (error instanceof TryAsyncError) {
* console.log(`Operation "${error.operation}" failed`);
* console.log(`Original error:`, error.originalError);
* }
* }
* );
* ```
*/
try_async<NewResultType>(fn: (value: ResultType) => Promise<NewResultType>): AsyncResult<NewResultType, ErrorType | TryAsyncError>;
/**
* Executes an async function with the contained value if Ok, and wraps the result in a Result.
* If this AsyncResult is Error, the function is not called and the error is propagated.
* If the async function throws or rejects, the error is caught and passed to the provided error mapper.
*
* **Important**: The error mapper function should not throw. If it does throw,
* the thrown error will be unhandled.
*
* @template NewResultType - The type of the value returned by the async function
* @template NewErrorType - The type of the error returned by the error mapper
* @param fn - Async function that takes the Ok value and returns a Promise
* @param errorMapper - Function that maps the caught error to a specific error type
* @returns A new AsyncResult containing the result of the async function or a union of the original error and mapped error
*
* @example
* ```typescript
* // Chain async operations with custom error mapping
* const userData = await result.try_async(() => fetch('/api/user/123'))
* .try_async(
* response => response.json(),
* error => new JsonParseError(`Failed to parse response: ${error}`)
* )
* .map(user => user.name);
* ```
*/
try_async<NewResultType, NewErrorType extends Error>(fn: (value: ResultType) => Promise<NewResultType>, errorMapper: (error: unknown) => NewErrorType): AsyncResult<NewResultType, ErrorType | NewErrorType>;
/**
* Async iterator support. Yields the contained value if Ok, nothing if Error.
*
* @returns An async generator that yields the value if Ok, otherwise yields nothing
*
* @example
* ```typescript
* // Iterate over successful values
* for await (const value of result.try_async(() => fetchUser("123"))) {
* console.log(value.name); // Only executes if fetch succeeds
* }
*
* // Collect successful values from multiple async operations
* const users = [];
* for await (const user of result.try_async(() => fetchUser("456"))) {
* users.push(user);
* }
* ```
*/
[Symbol.asyncIterator](): AsyncGenerator<ResultType, void, unknown>;
}
/**
* Executes a function and wraps the result in a Result type.
* If the function executes successfully, returns an Ok Result with the return value.
* If the function throws an error, returns an Error Result with the caught error.
*
* @template T - The return type of the function
* @param fn - A function that may throw an error
* @returns A Result containing either the function's return value or the caught error
*
* @example
* ```typescript
* // Working with a function that might throw
* function parseJSON(jsonString: string): any {
* return JSON.parse(jsonString); // Throws SyntaxError for invalid JSON
* }
*
* const validResult = result.try(() => parseJSON('{"name": "John"}'));
* if (validResult.is_ok()) {
* console.log(validResult.value.name); // "John"
* }
*
* const invalidResult = result.try(() => parseJSON('invalid json'));
* if (invalidResult.is_error()) {
* console.log(invalidResult.error.message); // "Unexpected token i in JSON at position 0"
* }
*
* // Converting existing throwing APIs
* const fileContent = result.try(() => fs.readFileSync('file.txt', 'utf8'));
* const parsedNumber = result.try(() => {
* const num = parseInt(userInput);
* if (isNaN(num)) throw new Error("Not a valid number");
* return num;
* });
*
* // With custom error mapping
* class ValidationError extends Error {
* field: string;
* constructor(message: string, field: string) {
* super(message);
* this.name = "ValidationError";
* this.field = field;
* }
* }
*
* const parseJson = (jsonString: string) =>
* result.try(
* () => JSON.parse(jsonString),
* (error) => new ValidationError(`Invalid JSON: ${String(error)}`, "json")
* );
*
* const invalidResult = parseJson("invalid json");
* if (invalidResult.is_error()) {
* console.log(invalidResult.error.field); // "json"
* console.log(invalidResult.error instanceof ValidationError); // true
* }
*
* // Note: Error mappers should not throw. If they do, the thrown error will be unhandled.
* ```
*/
declare function tryImpl<T>(fn: () => T): Result<T, Error>;
declare function tryImpl<T, ErrorType extends Error>(fn: () => T, errorMapper: (error: unknown) => ErrorType): Result<T, ErrorType>;
/**
* Executes an async function and wraps the result in an `AsyncResult`.
* The `AsyncResult` is a `PromiseLike` that supports the Result method chaining interfaces,
* and it can be `await`ed to access the `Result` and its contained value or error.
* If the function resolves successfully, the AsyncResult will contain an Ok Result with the resolved value.
* If the function rejects or throws, the AsyncResult will contain an Error Result with the caught error.
* To access the final `Result`, you will need to first `await` the `AsyncResult`.
*
* @template T - The resolved type of the async function
* @param fn - An async function that may reject or throw
* @returns An AsyncResult that can be chained immediately or awaited to get the final Result
*
* @example
* ```typescript
* // Immediate chaining without intermediate awaits
* const processedUser = result.try_async(() => fetchUserData("123"))
* .map(user => ({ ...user, name: user.name.toUpperCase() }))
* .and_then(user => user.name ? result.ok(user) : result.error(new Error("Invalid name")))
* .or_else(() => result.ok(createDefaultUser()));
*
* // Only await when you need the final result
* const finalUser = await processedUser;
* if (finalUser.is_ok()) {
* console.log("Processed user:", finalUser.value.name);
* }
*
* // Converting Promise-based APIs with chaining
* const fileData = await result.try_async(() => fs.promises.readFile('file.txt', 'utf8'))
* .map(content => content.trim())
* .and_then(content => content.length > 0 ? result.ok(content) : result.error(new Error("Empty file")));
*
* // With custom error mapping
* class NetworkError extends Error {
* statusCode: number;
* constructor(message: string, statusCode: number) {
* super(message);
* this.name = "NetworkError";
* this.statusCode = statusCode;
* }
* }
*
* const fetchData = async (url: string) =>
* result.try_async(
* () => fetch(url).then(r => r.json()),
* (error) => new NetworkError(`Request failed: ${String(error)}`, 500)
* );
*
* const userData = await fetchData('/api/user/123');
* if (userData.is_error()) {
* console.log(userData.error.statusCode); // 500
* console.log(userData.error instanceof NetworkError); // true
* }
* ```
*/
declare function tryAsyncImpl<T>(fn: () => Promise<T>): AsyncResult<T, Error>;
declare function tryAsyncImpl<T, ErrorType extends Error>(fn: () => Promise<T>, errorMapper: (error: unknown) => ErrorType): AsyncResult<T, ErrorType>;
/**
* Factory functions for creating Result instances.
* This module provides the primary API for constructing Result values.
*
* @property {function} ok - Creates a successful Result containing the provided value
* @property {function} error - Creates a failed Result containing the provided error
* @property {function} ok_async - Creates an already-resolved AsyncResult containing the provided value
* @property {function} error_async - Creates an already-resolved AsyncResult containing the provided error
* @property {function} try - Executes a function and wraps the result in a Result type
* @property {function} try_async - Executes an async function and returns an awaitable AsyncResult that supports immediate chaining
* @property {function} retry - Retries a Result-returning function multiple times until success
* @property {function} retry_async - Retries an async Result-returning function multiple times until success
*
* @example
* ```typescript
* import { result, type Result } from "./result.ts";
*
* // Creating success results
* const success = result.ok("Hello, World!");
* const number = result.ok(42);
* const nullValue = result.ok(null);
*
* // Creating error results
* const failure = result.error(new Error("Something went wrong"));
* const customError = result.error(new TypeError("Type mismatch"));
*
* // Chaining operations
* const processed = result.ok(" hello ")
* .map(str => str.trim())
* .map(str => str.toUpperCase())
* .and_then(str => str.length > 0 ? result.ok(str) : result.error(new Error("Empty string")));
* ```
*/
declare const result: {
/**
* Creates a successful Result containing the provided value.
* The value can be of any type, including null and undefined.
*
* @template ResultType - The type of the success value
* @template ErrorType - The type of potential errors (defaults to Error)
* @param value - The value to wrap in a successful Result
* @returns A Result containing the provided value
*
* @example
* ```typescript
* const stringValue = result.ok("Hello");
* const numberValue = result.ok(42);
* const objectValue = result.ok({ name: "John", age: 30 });
* const nullValue = result.ok(null);
* const undefinedValue = result.ok(undefined);
*
* // All of these are Ok Results
* console.log(stringValue.is_ok()); // true
* console.log(numberValue.value_or(0)); // 42
* ```
*/
readonly ok: <ResultType, ErrorType extends Error = Error>(value: ResultType) => Result<ResultType, ErrorType>;
/**
* Creates a failed Result containing the provided error.
* The error must be an instance of Error or a subclass of Error.
*
* @template ResultType - The type of potential success values
* @template ErrorType - The type of the error (defaults to Error)
* @param error - The error to wrap in a failed Result
* @returns A Result containing the provided error
*
* @example
* ```typescript
* const basicError = result.error(new Error("Basic error"));
* const typeError = result.error<string, TypeError>(new TypeError("Wrong type"));
* const customError = result.error(new RangeError("Out of range"));
*
* // Explicitly typed error results
* const parseError: Result<number, Error> = result.error<number, Error>(new Error("Parse failed"));
* const validationError = result.error<User, ValidationError>(new ValidationError("Invalid data"));
*
* // All of these are Error Results
* console.log(basicError.is_error()); // true
* if (typeError.is_error()) {
* console.log(typeError.error.message); // "Wrong type"
* }
*
* // Custom error classes work too
* class ValidationError extends Error {
* field: string;
* constructor(message: string, field: string) {
* super(message);
* this.name = "ValidationError";
* this.field = field;
* }
* }
* ```
*/
readonly error: <ResultType, ErrorType extends Error = Error>(error: ErrorType) => Result<ResultType, ErrorType>;
/**
* Creates an AsyncResult that has already resolved to an Ok Result.
* Useful for synchronous functions that must return AsyncResult
* because one or more branches invoke async code.
*
* @template ResultType - The type of the success value
* @template ErrorType - The type of potential errors (defaults to Error)
* @param value - The non-Promise value to wrap in an already-resolved AsyncResult
* @returns An AsyncResult that resolves to an Ok Result containing the provided value
*
* @example
* ```typescript
* async function fetchOrFallback(id: string): AsyncResult<User, Error> {
* const cached = cache.get(id);
* if (cached) {
* return result.ok_async(cached);
* }
* return result.try_async(() => fetchUser(id));
* }
* ```
*/
readonly ok_async: <ResultType, ErrorType extends Error = Error>(value: NonPromiseValue<ResultType>) => AsyncResult<ResultType, ErrorType>;
/**
* Creates an AsyncResult that has already resolved to an Error Result.
* Useful for synchronous functions that must return AsyncResult
* because one or more branches invoke async code.
*
* @template ResultType - The type of potential success values
* @template ErrorType - The type of the error (defaults to Error)
* @param error - The error to wrap in an already-resolved AsyncResult
* @returns An AsyncResult that resolves to an Error Result containing the provided error
*
* @example
* ```typescript
* async function createUser(input: UserInput): AsyncResult<User, ValidationError> {
* const validationIssue = validate(input);
* if (validationIssue) {
* return result.error_async<User, ValidationError>(validationIssue);
* }
* return result.try_async(() => persist(input));
* }
* ```
*/
readonly error_async: <ResultType, ErrorType extends Error = Error>(error: ErrorType) => AsyncResult<ResultType, ErrorType>;
readonly try: typeof tryImpl;
readonly try_async: typeof tryAsyncImpl;
/**
* Retries a result-returning function until it succeeds or has failed for all of the requested retries.
* If the function returns an Ok Result, the retry operation stops and returns that successful Result.
* If the function returns an Error Result, it's retried up to the specified number of times.
* If all retries fail, returns an Error Result containing all the accumulated errors.
*
* @template ValueType - The type of the ok (success) value
* @template ErrorType - The type of the error (must extend Error)
* @param fn - Function that returns a Result and may be retried
* @param retries - Maximum number of attempts to make (0 means no attempts)
* @returns A Result containing either the successful value or a retry error with all accumulated errors
*
* @example
* ```typescript
* let attempts = 0;
* function unreliableOperation(): Result<string, Error> {
* attempts++;
* if (attempts < 3) {
* return result.error(new Error(`Attempt ${attempts} failed`));
* }
* return result.ok("Success!");
* }
*
* const retryResult = result.retry(unreliableOperation, 5);
* if (retryResult.is_ok()) {
* console.log(retryResult.value); // "Success!"
* }
*
* // Network request example
* function fetchData(): Result<string, Error> {
* // Simulated network request that might fail
* return Math.random() > 0.7
* ? result.ok("Data fetched successfully")
* : result.error(new Error("Network timeout"));
* }
*
* const networkResult = result.retry(fetchData, 3);
* networkResult.match({
* on_ok: (data) => console.log("Got data:", data),
* on_error: (error) => console.log("All retries failed:", error.errors.map(e => e.message))
* });
*
* // Can be chained with other Result operations
* const processedResult = result.retry(fetchData, 3)
* .map(data => data.toUpperCase())
* .and_then(data => data.includes("SUCCESS") ? result.ok(data) : result.error(new Error("Invalid data")));
* ```
*/
readonly retry: <ValueType, ErrorType extends Error>(fn: () => Result<ValueType, ErrorType>, retries: number) => Result<ValueType, RetryError<ErrorType>>;
/**
* Retries a Promise<Result> returning function until it succeeds or has failed for all of the requested retries.
* If the function returns a Promise that resolves to an Ok Result, the retry operation stops and returns that successful Result.
* If the function returns a Promise that resolves to an Error Result, it's retried up to the specified number of times.
* If all retries fail, returns a Promise that resolves to an Error Result containing all the accumulated errors.
*
* @template ValueType - The type of the success value
* @template ErrorType - The type of the error (must extend Error)
* @param fn - Async function that returns a Promise<Result> and may be retried
* @param retries - Maximum number of attempts to make (0 means no attempts)
* @returns A Promise resolving to a Result containing either the successful value or a retry error with all accumulated errors
*
* @example
* ```typescript
* let attempts = 0;
* async function unreliableAsyncOperation(): Promise<Result<string, Error>> {
* attempts++;
* await new Promise(resolve => setTimeout(resolve, 100)); // Simulate async work
* if (attempts < 3) {
* return result.error(new Error(`Async attempt ${attempts} failed`));
* }
* return result.ok("Async success!");
* }
*
* const retryResult = await result.retry_async(unreliableAsyncOperation, 5);
* if (retryResult.is_ok()) {
* console.log(retryResult.value); // "Async success!"
* }
*
* // Network request example
* async function fetchDataAsync(): Promise<Result<string, Error>> {
* return result.try_async(async () => {
* const response = await fetch('/api/data');
* if (!response.ok) {
* throw new Error(`HTTP ${response.status}`);
* }
* const data = await response.text();
* return result.ok(data);
* })
* }
*
* const networkResult = await result.retry_async(fetchDataAsync, 3);
* networkResult.match({
* on_ok: (data) => console.log("Got data:", data),
* on_error: (error) => console.log("All retries failed:", error.errors.map(e => e.message))
* });
*
* // Can be chained with other Result operations
* const processedResult = await result.retry_async(fetchDataAsync, 3)
* .then(res => res.map(data => data.toUpperCase()))
* .then(res => res.and_then(data =>
* data.includes("SUCCESS") ? result.ok(data) : result.error(new Error("Invalid data"))
* ));
* ```
*/
readonly retry_async: <ValueType, ErrorType extends Error>(fn: () => Promise<Result<ValueType, ErrorType>>, retries: number) => Promise<Result<ValueType, RetryError<ErrorType>>>;
};
export { result, type Result, AsyncResult, type RetryError, type TryAsyncError, };
//# sourceMappingURL=result.d.ts.map