@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
TypeScript
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 {};