UNPKG

@rustable/enum

Version:

Rust-inspired pattern matching and type-safe error handling for TypeScript. Includes Option<T> for null-safety and Result<T, E> for error handling, with comprehensive pattern matching support

166 lines (165 loc) 6.46 kB
import { Constructor } from '@rustable/type'; /** * Decorator for creating enum variants. * Use this decorator to define static factory methods that create enum instances. * * @example * class Result<T, E> extends Enum { * @variant static Ok<T, E>(value: T): Result<T, E> { } * @variant static Err<T, E>(error: E): Result<T, E> { } * } * * @param target The class prototype * @param name The name of the variant * @param descriptor The property descriptor * @returns Modified property descriptor */ export declare function variant(target: any, name: string, descriptor: PropertyDescriptor): PropertyDescriptor; export interface DefaultMatch<U> { _: (() => U) | U; } type EnumMatchPatternBase<U, C> = C | (Partial<C> & DefaultMatch<U>); type EnumMatch<E extends Constructor, U> = { [K in keyof Omit<E, 'prototype'>]: E[K] extends (...args: infer P) => InstanceType<E> ? ((...args: P) => U) | U : never; }; export type EnumMatchPattern<U, C extends Constructor> = EnumMatchPatternBase<U, EnumMatch<C, U>>; export interface EnumModify { [key: string]: (...args: any[]) => any[]; } export interface EnumLetPattern<T extends (...args: any[]) => any, R> { if: (...args: Parameters<T>) => R; else: (() => R) | R; } export type EnumParam = Record<any, (...args: any[]) => any>; type CustomMatch<T, U extends EnumParam> = { [K in keyof U]: ((...args: Parameters<U[K]>) => T) | T; }; export type CustomModify<U extends EnumParam> = { [K in keyof U]: (...args: Parameters<U[K]>) => Parameters<U[K]>; }; export type EnumInstance<U extends EnumParam> = Omit<Enum, 'match' | 'modify' | 'clone' | 'eq' | 'is' | 'let'> & { match<T>(patterns: EnumMatchPatternBase<U, CustomMatch<T, U>>): T; modify(patterns: Partial<CustomModify<U>>): void; clone(): EnumInstance<U>; eq(other: EnumInstance<U>): boolean; } & { [P in keyof U as `is${Capitalize<string & P>}`]: () => boolean; } & { [P in keyof U as `let${Capitalize<string & P>}`]: <T>(cb: EnumLetPattern<U[P], T>) => T | undefined; }; export type CustomEnum<U extends EnumParam> = typeof Enum & { [K in keyof U]: (...args: Parameters<U[K]>) => EnumInstance<U>; }; export declare namespace Enums { /** * Creates a custom Enum class with the given variant definitions. * @param name Optional name for the created Enum class * @param variants An object defining the variants and their parameters * @returns A new custom Enum class with the specified variants * * @example * const SimpleEnum = Enums.create({ * A: () => {}, * B: (_x: number) => {}, * C: (_x: string, _y: number) => {}, * }); * * const a = SimpleEnum.A(); * const b = SimpleEnum.B(42); * const c = SimpleEnum.C('hello', 5); */ function create<U extends EnumParam>(variants: U): CustomEnum<U>; function create<U extends EnumParam>(name: string, variants: U): CustomEnum<U>; } /** * Base class for implementing Rust-style enums with pattern matching. * Provides a type-safe way to handle multiple variants of a type. * * @example * class Result<T, E> extends Enum { * @variant static Ok<T, E>(value: T): Result<T, E> { } * @variant static Err<T, E>(error: E): Result<T, E> { } * * unwrap(): T { * if (this.is('Ok')) return this.unwrapArg(); * throw new Error('Called unwrap on an Err value'); * } * } */ export declare class Enum<C extends Constructor = Constructor> { private name; private vars; constructor(name: string, ...vars: any[]); /** * Checks if the enum is a specific variant * @param variant The variant name to check * @returns true if the enum is the specified variant */ is(variant: string): boolean; /** * Checks if the enum is a specific variant and executes a callback if it matches * @param variant The variant name to check * @param callback The callback function to execute if the variant matches * @returns The result of the callback if variant matches, undefined otherwise */ let<T>(variant: string, cb: EnumLetPattern<(...arg: any[]) => T, T>): T; /** * Unwraps the first argument of a variant * @throws Error if the variant has no arguments * @returns The first argument of the variant */ unwrap<T>(): T; /** * Unwraps all arguments of a variant as a tuple * @throws Error if the variant has no arguments * @returns Tuple of all variant arguments */ unwrapTuple<T extends any[]>(): T; /** * Converts the enum to a string representation * Format: VariantName for variants without arguments * Format: VariantName(arg1, arg2, ...) for variants with arguments */ toString(): string; /** * Pattern matches on the enum variant, similar to Rust's enum expression * Use this method to handle different variants of the enum in a type-safe way. * * @param patterns Object mapping variant names to handler functions * @param defaultPatterns Optional default patterns to use if a variant isn't matched * @throws Error if no matching pattern is found and no default pattern is provided * @example * ```typescript * enum.enum({ * Success: (value) => `Got ${value}`, * Error: (err) => `Error: ${err.message}`, * }) * ``` */ match<U>(patterns: EnumMatchPatternBase<U, EnumMatch<C, U>>): U; /** * Checks if this enum instance equals another enum instance * Compares both variant names and their arguments */ eq(other: Enum<C>): boolean; /** * Creates a deep clone of the current enum instance * @returns A new instance of the enum with the same variant and cloned arguments */ clone(hash?: WeakMap<object, any>): this; /** * Replaces the current variant with a new one, returning the old variant * @param newVariant The new variant to replace with * @param ...args Arguments for the new variant * @throws Error if the new variant is not a valid variant of this enum * @returns The old variant instance */ replace(newInstance: Enum): this; /** * Modifies the arguments of the current variant based on the variant name * @param patterns Object mapping variant names to modifier functions * @throws Error if no matching pattern is found for the current variant */ modify(patterns: EnumModify): void; } export {};