UNPKG

@rustable/trait

Version:

A TypeScript library that implements Rust-like traits with compile-time type checking and runtime verification.

263 lines (262 loc) 8.68 kB
/** * Core trait system implementation for TypeScript * Provides Rust-like trait functionality with compile-time type checking and runtime verification. * * Key features: * - Type-safe trait definitions and implementations * - Support for generic traits * - Instance and static method implementations * - Trait-to-trait implementations * - Memory-efficient using WeakMap for garbage collection * - Performance optimized with parent trait caching * * @module @rustable/trait */ import { Constructor } from '@rustable/type'; /** * Symbol used to mark trait classes. */ declare const traitSymbol: unique symbol; /** * Type representing a trait implementation for a class. * Maps trait methods to their implementations. * * @template C The class type implementing the trait * @template T The trait being implemented */ export type TraitInstanceMethods<C extends Constructor, T extends TraitConstructor> = { [K in keyof InstanceType<T>]?: InstanceType<T>[K] extends (...args: infer P) => infer R ? (this: InstanceType<C>, ...args: P) => R : never; }; export type TraitStaticMethods<C extends Constructor, T extends TraitConstructor> = { [K in keyof Omit<T, 'isImplFor' | 'validFor' | 'wrap' | 'staticWrap' | 'implFor' | 'tryImplFor'>]?: T[K] extends (...args: infer P) => infer R ? (this: C, ...args: P) => R : never; }; export type TraitImplementation<C extends Constructor, T extends TraitConstructor> = TraitInstanceMethods<C, T> & { static?: TraitStaticMethods<C, T>; }; /** * Constructor type for commons. * Extends the base constructor with trait metadata. */ interface TraitConstructor<T = any> extends Constructor<T> { [traitSymbol]?: boolean; } /** * ITrait provides a type-safe wrapper for trait operations. * It offers a convenient API for trait checking, validation, and type conversion. * * Key features: * - Type-safe trait checking and conversion * - Support for both instance and static methods * - Automatic handling of multiple implementations * - Convenient trait implementation API * * @example * ```typescript * @trait * class Display extends ITrait { * display(): string { * return 'default'; * } * } * * class Point { * constructor(public x: number, public y: number) {} * } * * // Implement trait * Display.implFor(Point, { * display() { * return `(${this.x}, ${this.y})`; * } * }); * * // Use trait * const point = new Point(1, 2); * const display = Display.wrap(point); * console.log(display.display()); // "(1, 2)" * ``` */ export declare class Trait { static [traitSymbol]: boolean; /** * Checks if a value implements the trait. * This is a type-safe alternative to the hasTrait function. * * @param this The trait constructor * @param val The value to check * @returns true if the value implements the trait * * @example * ```typescript * @trait * class Display extends ITrait { * display(): string { * return 'default'; * } * } * * const point = new Point(1, 2); * if (Display.isImplFor(point)) { * // point implements Display trait * const display = Display.wrap(point); * console.log(display.display()); * } * ``` */ static isImplFor<T extends object>(this: Constructor<T>, val: any): boolean; /** * Validates that a value implements the trait. * Throws an error if the value does not implement the trait. * * @param this The trait constructor * @param val The value to validate * @throws {Error} if the value does not implement the trait * * @example * ```typescript * @trait * class Display extends ITrait { * display(): string { * return 'default'; * } * } * * // Throws if point doesn't implement Display trait * Display.validType(point); * ``` */ static validFor<T extends object>(this: Constructor<T>, val: any): void; /** * Wraps a value as an instance of the trait type. * Supports both instance and constructor wrapping, and automatically handles multiple implementations. * * @param this The trait constructor * @param val The value or constructor to wrap * @returns The wrapped trait instance or constructor * @throws {Error} if the value does not implement the trait * @throws {TraitMethodNotImplementedError} if accessing an unimplemented trait method * * @example * ```typescript * // Wrap instance * const point = new Point(1, 2); * const display = Display.wrap(point); * console.log(display.display()); * * // Wrap constructor * const PointDisplay = Display.wrap(Point); * const newPoint = new PointDisplay(3, 4); * ``` */ static wrap<T extends Constructor, C extends Constructor>(this: T, val: C, strict?: boolean): T; static wrap<T extends Constructor, C extends Constructor>(this: T, val: InstanceType<C>, strict?: boolean): InstanceType<T>; /** * Wraps a value as a static trait type. * Specifically handles static method trait wrapping and automatically handles multiple implementations. * * @param this The trait constructor * @param val The value or constructor to wrap * @returns The wrapped static trait constructor * @throws {Error} if the value does not implement the trait * @throws {TraitMethodNotImplementedError} if accessing an unimplemented static trait method * * @example * ```typescript * @trait * class FromStr extends ITrait { * static fromStr(s: string): any { * throw new Error('Not implemented'); * } * } * * // Wrap Point's static methods * const PointFromStr = FromStr.staticWrap(Point); * const point = PointFromStr.fromStr('1,2'); * ``` */ static staticWrap<T extends Constructor, C extends Constructor>(this: T, val: C | InstanceType<C>): T; /** * Implements the trait for a target class. * Provides a convenient API for implementing traits with support for default implementations. * * @param this The trait constructor * @param target The target class to implement the trait for * @param implementation Optional implementation overrides * * @example * ```typescript * @trait * class Display extends ITrait { * display(): string { * return 'default'; * } * } * * // Use custom implementation * Display.implFor(Point, { * display() { * return `(${this.x}, ${this.y})`; * } * }); * * // Use default implementation * Display.implFor(OtherClass); * ``` */ static implFor<T extends TraitConstructor, C extends Constructor>(this: T, target: C, implementation?: TraitImplementation<C, T>): void; /** * Tries to implement the trait for a target class. * Similar to implFor, but doesn't throw an error if the trait is already implemented. * * @param this The trait constructor * @param target The target class to implement the trait for * @param implementation Optional implementation overrides * * @example * ```typescript * @trait * class Display extends ITrait { * display(): string { * return 'default'; * } * } * * // Use custom implementation * Display.tryImplFor(Point, { * display() { * return `(${this.x}, ${this.y})`; * } * }); * * // Use default implementation * Display.tryImplFor(Point); * ``` */ static tryImplFor<T extends TraitConstructor, C extends Constructor>(this: T, target: C, implementation?: TraitImplementation<C, T>): void; } /** * Decorator for implementing traits at compile time. * Provides a more declarative way to implement traits using decorators. * * @param trait The trait to be implemented * @param implementation Optional implementation overrides * @returns A decorator function that applies the trait * * @example * ```typescript * const Display = macroTrait(DisplayTrait); * const FromStr = macroTrait(FromStrTrait); * * @derive([Display, FromStr]) * class Point { * constructor(public x: number, public y: number) {} * * // Override default display implementation * display(): string { * return `(${this.x}, ${this.y})`; * } * } * ``` */ export declare function macroTrait<C extends Constructor, T extends TraitConstructor>(trait: T, implementation?: TraitImplementation<C, T>): T & ((target: any) => void); export {};