UNPKG

wellcrafted

Version:

Delightful TypeScript patterns for elegant, type-safe applications

184 lines (182 loc) 6.26 kB
import { Err } from "../result-fCtNge01.js"; //#region src/error/types.d.ts /** * Base error structure for all errors in the Result system. * * Provides a consistent structure for error objects that are JSON-serializable * and contain comprehensive debugging information. * * @example * ```ts * const error: BaseError = { * name: "DatabaseError", * message: "Connection failed", * context: { host: "localhost", port: 5432 }, * cause: originalError * }; * ``` */ type BaseError = Readonly<{ name: string; message: string; context?: Record<string, unknown>; cause: unknown; }>; /** * Creates a tagged error type for type-safe error handling. * Uses the `name` property as a discriminator for tagged unions. * * Error types should follow the convention of ending with "Error" suffix. * The Err data structure wraps these error types in the Result system. * * @example * ```ts * type ValidationError = TaggedError<"ValidationError"> * type NetworkError = TaggedError<"NetworkError"> * * function handleError(error: ValidationError | NetworkError) { * switch (error.name) { * case "ValidationError": // TypeScript knows this is ValidationError * break; * case "NetworkError": // TypeScript knows this is NetworkError * break; * } * } * * // Used in Result types: * function validate(input: string): Result<string, ValidationError> { * if (!input) { * return Err({ * name: "ValidationError", * message: "Input is required", * context: { input }, * cause: null, * }); * } * return Ok(input); * } * * // Context is optional - omit when not needed: * function checkAuth(): Result<User, AuthError> { * if (!isAuthenticated) { * return Err({ * name: "AuthError", * message: "User not authenticated", * cause: null, * }); * } * return Ok(currentUser); * } * ``` */ type TaggedError<T extends string> = BaseError & { readonly name: T; }; //# sourceMappingURL=types.d.ts.map //#endregion //#region src/error/utils.d.ts /** * Extracts a readable error message from an unknown error value * * This utility is commonly used in mapErr functions when converting * unknown errors to typed error objects in the Result system. * * @param error - The unknown error to extract a message from * @returns A string representation of the error * * @example * ```ts * // With native Error * const error = new Error("Something went wrong"); * const message = extractErrorMessage(error); // "Something went wrong" * * // With string error * const stringError = "String error"; * const message2 = extractErrorMessage(stringError); // "String error" * * // With object error * const unknownError = { code: 500, details: "Server error" }; * const message3 = extractErrorMessage(unknownError); // '{"code":500,"details":"Server error"}' * * // Used in mapErr function * const result = await tryAsync({ * try: () => riskyOperation(), * mapErr: (error) => Err({ * name: "NetworkError", * message: extractErrorMessage(error), * context: { operation: "riskyOperation" }, * cause: error, * }), * }); * ``` */ declare function extractErrorMessage(error: unknown): string; /** * Input type for creating a tagged error (everything except the name) */ type TaggedErrorWithoutName<T extends string> = Omit<TaggedError<T>, "name">; /** * Replaces the "Error" suffix with "Err" suffix in error type names. * * This utility type is used to create companion function names for error constructors * that return Err-wrapped results, maintaining consistent naming conventions. * * @template T - An error type name that must end with "Error" * @returns The type name with "Error" replaced by "Err" * * @example * ```ts * type NetworkErr = ReplaceErrorWithErr<"NetworkError">; // "NetworkErr" * type ValidationErr = ReplaceErrorWithErr<"ValidationError">; // "ValidationErr" * type AuthErr = ReplaceErrorWithErr<"AuthError">; // "AuthErr" * ``` */ type ReplaceErrorWithErr<T extends `${string}Error`> = T extends `${infer TBase}Error` ? `${TBase}Err` : never; /** * Return type for createTaggedError - contains both factory functions. * * Provides two factory functions: * - One that creates plain TaggedError objects (named with "Error" suffix) * - One that creates Err-wrapped TaggedError objects (named with "Err" suffix) */ type TaggedErrorFactories<TErrorName extends `${string}Error`> = { [K in TErrorName]: (input: TaggedErrorWithoutName<K>) => TaggedError<K> } & { [K in ReplaceErrorWithErr<TErrorName>]: (input: TaggedErrorWithoutName<TErrorName>) => Err<TaggedError<TErrorName>> }; /** * Returns two different factory functions for tagged errors. * * Given an error name like "NetworkError", this returns: * - `NetworkError`: Creates a plain TaggedError object * - `NetworkErr`: Creates a TaggedError object wrapped in an Err result * * The naming pattern automatically replaces the "Error" suffix with "Err" suffix * for the Result-wrapped version. * * @param name - The name of the error type (must end with "Error") * @returns An object with two factory functions: * - [name]: Function that creates plain TaggedError objects * - [name with "Error" replaced by "Err"]: Function that creates Err-wrapped TaggedError objects * * @example * ```ts * const { NetworkError, NetworkErr } = createTaggedError('NetworkError'); * * // NetworkError: Creates just the error object * const error = NetworkError({ * message: 'Connection failed', * context: { url: 'https://api.example.com' }, * cause: undefined * }); * // Returns: { name: 'NetworkError', message: 'Connection failed', ... } * * // NetworkErr: Creates error and wraps in Err result * return NetworkErr({ * message: 'Connection failed', * context: { url: 'https://api.example.com' }, * cause: undefined * }); * // Returns: Err({ name: 'NetworkError', message: 'Connection failed', ... }) * ``` */ declare function createTaggedError<TErrorName extends `${string}Error`>(name: TErrorName): TaggedErrorFactories<TErrorName>; //#endregion export { BaseError, TaggedError, createTaggedError, extractErrorMessage }; //# sourceMappingURL=index.d.ts.map