/** * IronEnum – Zero-dependency Rust-style tagged-union helpers for TypeScript. * * A small utility to build runtime representations of discriminated unions, * with type-safe pattern matching and ergonomic Result/Option types. * * @example * // Define an enum * const Status = IronEnum<{ * Loading: undefined; * Ready: { finishedAt: Date }; * Error: { message: string; code: number }; * }>(); * * // Create instances * const s1 = Status.Loading(); * const s2 = Status.Ready({ finishedAt: new Date() }); * * // Narrow using .is() * if (s2.is("Ready")) { * s2.data.finishedAt.toISOString(); * } * * // Match with fallback * const msg = s2.match({ * Loading: () => "Working", * Ready: ({ finishedAt }) => finishedAt.toISOString(), * _: () => "Unknown" * }); * * // Exhaustive match (no fallback allowed) * const iso = s2.matchExhaustive({ * Loading: () => "n/a", * Ready: ({ finishedAt }) => finishedAt.toISOString(), * Error: () => "n/a", * }); * * @example * // Result and Option usage * const R = Result(); * const r1 = R.Ok(42); * const r2 = R.Err("nope"); * const val = r1.unwrap_or(0); // 42 * * const O = Option(); * const some = O.Some(7); * const none = O.None(); * const out = some.map(x => x * 2).unwrap(); // 14 */ /** * Structure of enum variants. * * Each key is a variant name and its value is the payload for that variant. * Use `undefined` for variants without associated data. * * @example * type MyVariants = { * Unit: undefined; * Tuple: [string, number]; * Record: { id: string }; * } */ export type VariantsRecord = { readonly [K in Exclude]: unknown; }; /** * Union of all possible enum variant instances for a given `VariantsRecord`. * * This is useful for function parameters that accept any variant instance. * This type is typically accessed via the `_.typeOf` property on a factory. * * @example * const Status = IronEnum<{ Ok: string; Err: Error }>(); * * // The `_.typeOf` property provides this union type. * function logStatus(s: typeof Status._.typeOf) { * // s is: IronEnumVariantUnion<{ Ok: string; Err: Error }> * console.log(s.tag); * } */ export type IronEnumVariantUnion = { [K in keyof ALL & string]: IronEnumVariant; }[keyof ALL & string]; /** * Constructor signature for a variant based on its payload type. * * - If the payload type is `undefined`, the constructor is nullary. * - If the payload is an object with only optional properties, the payload is optional. * - Otherwise, the constructor requires the payload. */ type RequiredKeys = { [K in keyof T]-?: {} extends Pick ? never : K; }[keyof T]; type HasOnlyOptionalObjectKeys = T extends object ? [RequiredKeys] extends [never] ? true : false : false; type VariantConstructor = [ Default ] extends [undefined] ? () => IronEnumVariant : HasOnlyOptionalObjectKeys extends true ? (data?: Default) => IronEnumVariant : (data: Default) => IronEnumVariant; /** * Return type calculation used by `if` and `ifNot`. * * Produces a boolean when both callbacks return `void`. * Otherwise, returns the union of defined callback return types plus boolean. */ type IfReturn = [RIf, RElse] extends [void, void] ? boolean : RIf extends void ? boolean | Exclude : RElse extends void ? boolean | Exclude : Exclude | Exclude; /** * A single constructed enum variant instance with its discriminant, payload, * a back-reference to the factory that created it, and matching utilities. * * @template TAG The discriminant string literal * @template PAYLOAD The payload type carried by this variant * @template ALL The full `VariantsRecord` for the enum */ export type IronEnumVariant = { /** Discriminant of the variant. */ readonly tag: TAG; /** Payload carried by the variant. */ readonly data: PAYLOAD; /** * The factory object this instance originated from. * * @example * const loading = Status.Loading(); * // Create a new variant from the same factory * const ready = loading.instance.Ready({ finishedAt: new Date() }); */ readonly instance: IronEnumFactory; } & EnumMethods; /** * Serializable wire format for a variant instance. * * Use with `JSON.stringify` and `Enum._.parse` / `Enum._.fromJSON` / * `Enum._.reviver` to move values across the wire safely. * * @example * const s = Status.Error({ message: "oops", code: 500 }); * const json = JSON.stringify(s); * // json === '{"tag":"Error","data":{"message":"oops","code":500}}' */ export type IronEnumWireFormat = { [K in keyof ALL & string]: { tag: K; data: ALL[K]; }; }[keyof ALL & string]; /** * Helper to exclude a specific variant from the union by its tag. */ type ExcludeVariant = Exclude, IronEnumVariant>; /** * Methods present on each variant instance. * * Includes: * - `toJSON` for structured logging/serialization. * - `is` / `if` / `ifNot` for quick predicates. * - `match` / `matchAsync` for flexible pattern matching. * - `matchExhaustive` for compile-time exhaustive handling. */ export interface EnumMethods { /** * Convert the instance into `{ tag, data }` for JSON or debugging. * Automatically called by `JSON.stringify`. * * @example * const s = Status.Ready({ finishedAt: new Date() }); * const json = JSON.stringify(s); * // json === '{"tag":"Ready","data":{...}}' */ toJSON(): { readonly tag: TAG; readonly data: ALL[TAG]; }; /** * Predicate that narrows the variant type on success. * * @example * if (state.is("Ready")) { * // state.data is narrow to Ready payload * state.data.finishedAt.toISOString(); * } */ is(key: K): this is IronEnumVariant; /** * Execute a callback when the discriminant equals `key`. * * When no callbacks are provided, acts as a boolean predicate. * When callbacks are provided, returns `true` or the callback's * result on success, and `false` or the failure callback's * result on failure. * * The `failure` callback receives a type-safe union of all * variants *except* the one being checked. * * @example * // As a predicate * if (state.if("Loading")) { * // ... * } * * // With a success callback * state.if("Ready", (data) => { * console.log(data.finishedAt); * }); * * // With both callbacks to extract a value * const message = state.if( * "Error", * (data) => `Error: ${data.message}`, * (other) => `Status: ${other.tag}` // other is Loading | Ready * ); */ if(key: K, success?: (payload: ALL[K], self: IronEnumVariant) => RIf, failure?: (self: ExcludeVariant) => RElse): IfReturn; /** * Execute a callback when the discriminant does NOT equal `key`. * * The `success` callback receives a type-safe union of all * variants *except* the one being checked. * * @example * // As a predicate * if (state.ifNot("Error")) { * // state is Loading | Ready * } * * // With a success callback * state.ifNot("Loading", (other) => { * // other is Ready | Error * console.log(`Not loading: ${other.tag}`); * }); */ ifNot(key: K, success?: (self: ExcludeVariant) => RIf, failure?: (payload: ALL[K], self: IronEnumVariant) => RElse): IfReturn; /** * Pattern matching with optional `_` fallback arm. * * Use when some variants can be handled together via a fallback. * * @example * // Exhaustive match * const httpStatus = state.match({ * Loading: () => 202, * Ready: () => 200, * Error: ({ code }) => code, * }); * * // With a fallback * const message = state.match({ * Error: ({ message }) => message, * _: (self) => `Current state: ${self.tag}`, * }); */ match>(callbacks: A): MatchResult; /** * Asynchronous pattern matching with optional `_` fallback arm. * All callbacks must return a `Promise`. * * @example * const data = await state.matchAsync({ * Loading: async () => fetch("/data"), * Ready: async (data) => data.finishedAt, * _: async () => null * }); */ matchAsync>(callbacks: A): Promise>; /** * Exhaustive pattern matching. All variants must be handled. * * No `_` fallback is allowed. Compilation fails if a case is missing. * * @example * const message = state.matchExhaustive({ * Loading: () => "Still loading...", * Ready: ({ finishedAt }) => `Done at ${finishedAt}`, * Error: ({ message }) => `Failed: ${message}`, * }); */ matchExhaustive>(callbacks: A): MatchResult; } type NonOptional = { [K in keyof T]-?: T[K]; }; /** Map each tag to a synchronous handler `(payload, self) => R`. */ type ObjectToFunctionMapBase = { [K in keyof T]?: (payload: T[K], self: IronEnumVariant) => R; }; /** Sync handler options. */ type ObjectToFunctionMap = ObjectToFunctionMapBase; /** Async handler options. */ type ObjectToFunctionMapAsync = ObjectToFunctionMapBase>; /** * Valid sync match configurations: * 1) Provide all tags, or * 2) Provide partial tags plus `_` fallback. */ type MatchFns = NonOptional> | (ObjectToFunctionMap & { _: (self: IronEnumVariantUnion) => any; }); /** * Valid async match configurations: * 1) Provide all tags, or * 2) Provide partial tags plus `_` fallback. */ type MatchFnsAsync = NonOptional> | (ObjectToFunctionMapAsync & { _: (self: IronEnumVariantUnion) => Promise; }); /** Exhaustive mapping: all tags required, no `_` fallback allowed. */ type ExhaustiveFns = { [K in keyof X & string]: (payload: X[K], self: IronEnumVariant) => any; }; /** Extract the unified return type of a match dispatch. */ type MatchResult = A extends { [K: string]: (...args: any) => infer R; } ? R : never; /** * Runtime factory for an enum, where each key is a constructor for its variant. * * @example * const Status = IronEnum<{ * Loading: undefined; * Ready: { count: number }; * }>(); * * const s1 = Status.Loading(); // { tag: "Loading", data: undefined } * const s2 = Status.Ready({ count: 1 }); // { tag: "Ready", data: { count: 1 } } */ export type IronEnumFactory = { [K in keyof ALL & string]: VariantConstructor; } & { /** * Utilities and [TYPE ONLY] metadata exposed via the `_` property. * * The fields marked [TYPE ONLY] exist only for type access in code and do not * exist at runtime. They intentionally evaluate to `never` at runtime. */ _: EnumProperties; }; /** * Utility metadata exposed on the factory via `_`. * * Includes parsers and [TYPE ONLY] accessors for tags, payload union, and * the union instance type. */ export type EnumProperties = { /** * [TYPE ONLY] Union of tag names. * * @example * const Status = IronEnum<{ A: 0; B: 1 }>(); * type StatusTags = typeof Status._.typeTags; // "A" | "B" */ readonly typeTags: keyof ALL & string; /** * [TYPE ONLY] Union of payload values. * * @example * const Status = IronEnum<{ A: 0; B: 1 }>(); * type StatusData = typeof Status._.typeData; // 0 | 1 */ readonly typeData: ALL[keyof ALL]; /** * [TYPE ONLY] The generic json format exported by `toJSON` and parsed by `_.parse`. * * @example * const Status = IronEnum<{ A: 0; B: 1 }>(); * * function process(s: typeof Status._.typeJson) { * const p = Status._.parse(s); * } * * process(Status.A(0).toJSON()); * */ readonly typeJson: IronEnumWireFormat; /** * [TYPE ONLY] Union of all variant instances for this enum. * This is the main type to use in function signatures or return statements. * * @example * const Status = IronEnum<{ A: 0; B: 1 }>(); * * function process(s: typeof Status._.typeOf) { * // ... * } * * process(Status.A(0)); */ readonly typeOf: IronEnumVariantUnion & AddedProps; /** * Parse `{ tag, data }` into a variant instance. * If the keys where provided to the original function call then throws when the tag is not recognized by this factory. * * @example * const data = { tag: "Ready", data: { finishedAt: new Date() } } as const; * const s = Status._.parse(data); * if (s.is("Ready")) { ... } */ parse(dataObj: ALL[TAG] extends undefined ? { tag: TAG; data?: ALL[TAG]; } : { tag: TAG; data: ALL[TAG]; }): IronEnumVariant; /** * Alias of `parse`. Convenient for deserializers. * @see parse */ fromJSON(dataObj: ALL[TAG] extends undefined ? { tag: TAG; data?: ALL[TAG]; } : { tag: TAG; data: ALL[TAG]; }): IronEnumVariant; /** * JSON.parse reviver. Pass as the reviver to automatically convert * nested `{ tag, data }` shapes for this enum. * * @example * const text = '{"tag":"Ready","data":{...}}'; * const s = JSON.parse(text, (k, v) => Status._.reviver(v)); * // s is now a full Status.Ready variant instance */ reviver(obj: unknown): IronEnumVariantUnion | unknown; }; /** * Create a new enum factory. * * @param args - Optional arguments. * @param args.keys - An array of variant keys. Providing this skips the * Proxy-based implementation for a faster, pre-bound factory. * * @example * // Dynamic (Proxy-based, slower) * const Status = IronEnum<{ * A: undefined; * B: undefined; * }>(); * * // Pre-bound (Fast, no Proxy) * const FastStatus = IronEnum<{ * A: undefined; * B: undefined; * }>({ keys: ["A", "B"] }); */ export declare function IronEnum(args?: { keys?: (keyof ALL & string)[]; }): "_" extends keyof ALL ? "ERROR: '_' is reserved!" : IronEnumFactory; /** * Methods common to success-carrying types that allow extracting values, * defaults, or lazily computed fallbacks. */ type ExtendedRustMethods = { /** * Return the success value. * **Throws** if the variant is `Err` or `None`. * * @example * Ok(1).unwrap(); // 1 * Err("!").unwrap(); // Throws * None().unwrap(); // Throws */ unwrap(): T; /** * Return the success value or a provided default. * * @example * Ok(1).unwrap_or(0); // 1 * Err("!").unwrap_or(0); // 0 * None().unwrap_or(0); // 0 */ unwrap_or(value: R): R | T; /** * Return the success value or the result of a fallback function. * The callback is only executed if needed. * * @example * Ok(1).unwrap_or_else(() => 0); // 1 * Err("!").unwrap_or_else(() => 0); // 0 * None().unwrap_or_else(() => expensive_calc()); // 0 */ unwrap_or_else(cb: () => R): R | T; }; /** * Result-specific helpers for mapping and chaining. */ type ResultMethods = { /** * Convert `Result` to `Option`, dropping the error. * * @example * Ok(1).ok(); // Some(1) * Err("!").ok(); // None() */ ok(): OptionVariant<{ Some: ALL["Ok"]; None: undefined; }>; /** * Predicate for `Ok` variant. * * @example * if (myResult.isOk()) { ... } */ isOk(): boolean; /** * Predicate for `Err` variant. * * @example * if (myResult.isErr()) { ... } */ isErr(): boolean; /** * Map the `Ok` value, leaving `Err` untouched. * * @example * Ok(1).map(x => x + 1); // Ok(2) * Err("!").map(x => x + 1); // Err("!") */ map(f: (t: ALL["Ok"]) => U): ResultVariant<{ Ok: U; Err: ALL["Err"]; }>; /** * Map the `Err` value, leaving `Ok` untouched. * * @example * Ok(1).mapErr(x => x + "!"); // Ok(1) * Err("!").mapErr(x => x + "!"); // Err("!!") */ mapErr(f: (e: ALL["Err"]) => F): ResultVariant<{ Ok: ALL["Ok"]; Err: F; }>; /** * Chain a new `Result`-returning operation when `Ok`. * Also known as `flatMap`. * * @example * const safeDivide = (n: number) => n === 0 ? Err("div by 0") : Ok(10 / n); * * Ok(5).andThen(safeDivide); // Ok(2) * Ok(0).andThen(safeDivide); // Err("div by 0") * Err("!").andThen(safeDivide); // Err("!") */ andThen(f: (t: ALL["Ok"]) => ResultVariant<{ Ok: U; Err: ALL["Err"]; }>): ResultVariant<{ Ok: U; Err: ALL["Err"]; }>; }; /** * A Result instance (Ok or Err) with extraction and mapping helpers. * * This type is invariant, meaning `Result` is not assignable * to `Result`. * * To accept `Result` in a function, either use a specific factory: * @example * const MyResult = Result(); * function process(r: typeof MyResult._.typeOf) { ... } * * // Or make the function generic: * function process(r: ResultVariant<{ Ok: T, Err: E }>) { ... } */ export type ResultVariant = IronEnumVariant & ExtendedRustMethods & ResultMethods; /** * Factory for creating Ok and Err variants plus metadata via `_`. * * @example * const R = Result(); * const r1 = R.Ok(1); * const r2 = R.Err("nope"); */ export type ResultFactory = { Ok(data: ALL["Ok"]): IronEnumVariant<"Ok", ALL["Ok"], ALL> & ExtendedRustMethods & ResultMethods; Err(data: ALL["Err"]): IronEnumVariant<"Err", ALL["Err"], ALL> & ExtendedRustMethods & ResultMethods; _: EnumProperties & ResultMethods>; }; /** * Create a typed Result factory ``. * * @example * const StringResult = Result(); * const r1 = StringResult.Ok("hello"); * * function process(r: typeof StringResult._.typeOf) { * // ... * } */ export declare const Result: () => ResultFactory<{ Ok: T; Err: E; }>; /** * Convenience Ok constructor for ad-hoc success values. * The `Err` type is `never`. * * @example * const r = Ok(123); // ResultVariant<{ Ok: number, Err: never }> */ export declare const Ok: (value: T) => ResultVariant<{ Ok: T; Err: never; }>; /** * Convenience Err constructor for ad-hoc error values. * The `Ok` type is `never`. * * @example * const r = Err("oops"); // ResultVariant<{ Ok: never, Err: string }> */ export declare const Err: (error: E) => ResultVariant<{ Ok: never; Err: E; }>; /** * Option-specific helpers for converting to Result, mapping, chaining, and * basic predicates. */ type OptionMethods = { /** * Convert `Some(T)` to `Ok(T)` or `None` to `Err(E)`. * * @example * Some(1).ok_or("!"); // Ok(1) * None().ok_or("!"); // Err("!") */ ok_or(err: E): ResultVariant<{ Ok: OK; Err: E; }>; /** * Convert `Some(T)` to `Ok(T)` or `None` to `Err(E)` * using a lazily-computed error. * * @example * Some(1).ok_or_else(() => "!"); // Ok(1) * None().ok_or_else(() => "!"); // Err("!") */ ok_or_else(err: () => E): ResultVariant<{ Ok: OK; Err: E; }>; /** * Predicate for `Some` variant. * * @example * if (myOption.isSome()) { ... } */ isSome(): boolean; /** * Predicate for `None` variant. * * @example * if (myOption.isNone()) { ... } */ isNone(): boolean; /** * Map the `Some` value, leaving `None` untouched. * * @example * Some(1).map(x => x + 1); // Some(2) * None().map(x => x + 1); // None() */ map(f: (t: OK) => U): OptionVariant<{ Some: U; None: undefined; }>; /** * Chain a new `Option`-returning operation when `Some`. * Also known as `flatMap`. * * @example * const firstChar = (s: string) => s.length > 0 ? Some(s[0]) : None(); * * Some("hi").andThen(firstChar); // Some("h") * Some("").andThen(firstChar); // None() * None().andThen(firstChar); // None() */ andThen(f: (t: OK) => OptionVariant<{ Some: U; None: undefined; }>): OptionVariant<{ Some: U; None: undefined; }>; /** * Keep `Some` only when the predicate passes. * * @example * Some(2).filter(x => x % 2 === 0); // Some(2) * Some(1).filter(x => x % 2 === 0); // None() * None().filter(x => x % 2 === 0); // None() */ filter(p: (t: OK) => boolean): OptionVariant<{ Some: OK; None: undefined; }>; }; /** * Option instance (Some or None) enriched with extraction and mapping helpers. * * This type is invariant. See `ResultVariant` for notes on usage. */ export type OptionVariant = IronEnumVariant & ExtendedRustMethods & OptionMethods; /** * Factory for creating Some and None variants plus metadata via `_`. * * @example * const O = Option(); * const s = O.Some(1); * const n = O.None(); */ export type OptionFactory = { Some(data: ALL["Some"]): IronEnumVariant<"Some", ALL["Some"], ALL> & ExtendedRustMethods & OptionMethods; None(): IronEnumVariant<"None", ALL["None"], ALL> & ExtendedRustMethods & OptionMethods; _: EnumProperties & OptionMethods>; }; /** * Create a typed Option factory ``. * * @example * const NumberOption = Option(); * const s = NumberOption.Some(100); * * function process(o: typeof NumberOption._.typeOf) { * // ... * } */ export declare const Option: () => OptionFactory<{ Some: T; None: undefined; }>; /** * Convenience Some constructor for ad-hoc values. * * @example * const s = Some(123); // OptionVariant<{ Some: number, ... }> */ export declare const Some: (value: T) => OptionVariant<{ Some: T; None: undefined; }>; /** * Convenience None constructor. * The `Some` type is `never`. * * @example * const n = None(); // OptionVariant<{ Some: never, ... }> */ export declare const None: () => OptionVariant<{ Some: never; None: undefined; }>; /** * Convert exception-throwing code into Result-returning code. */ export declare const Try: { /** * Execute a synchronous function and wrap the outcome. * Ok on success, Err with the caught exception on failure. */ sync(cb: () => X): ResultVariant<{ Ok: X; Err: unknown; }>; /** * Execute an asynchronous function and wrap the outcome. * Resolves to Ok on success, Err with the caught exception on rejection. */ async(cb: () => Promise): Promise>; }; /** * Transform functions to return Result instead of throwing. */ export declare const TryInto: { /** * Wrap a synchronous function. The wrapper never throws. */ sync(cb: (...args: Y) => X): (...args: Y) => ResultVariant<{ Ok: X; Err: unknown; }>; /** * Wrap an asynchronous function. The wrapper resolves to Result. */ async(cb: (...args: Y) => Promise): (...args: Y) => Promise>; }; export {}; //# sourceMappingURL=mod.d.ts.map