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