npm.io
0.4.12 • Published 1 year ago

@rustable/trait

Licence
MIT
Version
0.4.12
Deps
1
Size
43 kB
Vulns
0
Weekly
0
Stars
18

@rustable/trait

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

Features

  • Type Safety - Type-safe trait definitions and implementations
  • Generics - Support for generic traits and implementations
  • Methods - Instance and static method implementations
  • Composition - Trait-to-trait implementations
  • Memory - Memory-efficient using WeakMap for GC

Installation

npm install @rustable/trait
# or
yarn add @rustable/trait
# or
pnpm add @rustable/trait

Usage

Defining a Trait
import { Trait, macroTrait } from '@rustable/trait';

// Define a trait
class DisplayTrait extends Trait {
  display(): string {
    return 'default';
  }
}

// Create a trait decorator
const Display = macroTrait(DisplayTrait);
Implementing a Trait

There are several ways to implement a trait:

  1. Using the @derive decorator with default implementation:
@derive([Display])
class Point {
  constructor(
    public x: number,
    public y: number,
  ) {}
}

// The display method will use the default implementation from DisplayTrait
  1. Using implFor method with custom implementation:
class Point {
  constructor(
    public x: number,
    public y: number,
  ) {}
}

DisplayTrait.implFor(Point, {
  display() {
    return `(${this.x}, ${this.y})`;
  },
});
Using Traits

Once a trait is implemented, you can use it in several ways:

const point = new Point(1, 2);

// Method 1: Using wrap
const display = DisplayTrait.wrap(point);
console.log(display.display()); // "(1, 2)"

// Method 2: Checking implementation
if (DisplayTrait.isImplFor(point)) {
  const display = DisplayTrait.wrap(point);
  console.log(display.display());
}
Static Trait Methods

Traits can also include static methods:

class FromStrTrait extends Trait {
  static fromStr(s: string): any {
    throw new Error('Not implemented');
  }
}

const FromStr = macroTrait(FromStrTrait);

class Point {
  constructor(
    public x: number,
    public y: number,
  ) {}
}

// Implement static methods using implFor
FromStr.implFor(Point, {
  static: {
    fromStr(s: string): Point {
      const [x, y] = s.split(',').map(Number);
      return new Point(x, y);
    },
  },
});

// Use static trait methods
const point = FromStrTrait.staticWrap(Point).fromStr('1,2');

API Reference

Core Functions
macroTrait

Creates a trait decorator for implementing traits at compile time.

const Display = macroTrait(DisplayTrait);
const FromStr = macroTrait(FromStrTrait);

@derive([Display, FromStr])
class Point {
  constructor(
    public x: number,
    public y: number,
  ) {}
}

// Implement custom behavior using implFor
DisplayTrait.implFor(Point, {
  display() {
    return `(${this.x}, ${this.y})`;
  },
});

FromStrTrait.implFor(Point, {
  static: {
    fromStr(s: string): Point {
      const [x, y] = s.split(',').map(Number);
      return new Point(x, y);
    },
  },
});
Trait Class Methods

The Trait class provides several static methods for trait operations:

isImplFor

Checks if a value implements the trait.

if (DisplayTrait.isImplFor(point)) {
  // point implements DisplayTrait
  const display = DisplayTrait.wrap(point);
  console.log(display.display());
}
validFor

Validates that a value implements the trait. Throws if validation fails.

// Throws if point doesn't implement DisplayTrait
DisplayTrait.validFor(point);
wrap

Wraps a value as a trait instance. Supports both instance and constructor wrapping.

// Wrap instance
const point = new Point(1, 2);
const display = DisplayTrait.wrap(point);
console.log(display.display());

// Wrap constructor
const PointDisplay = DisplayTrait.wrap(Point);
const newPoint = new PointDisplay(3, 4);
staticWrap

Wraps a class to access static trait methods.

// Wrap Point's static methods
const PointFromStr = FromStrTrait.staticWrap(Point);
const point = PointFromStr.fromStr('1,2');
implFor

Implements a trait for a target class.

DisplayTrait.implFor(Point, {
  display() {
    return `(${this.x}, ${this.y})`;
  },
});
tryImplFor

Similar to implFor, but doesn't throw if the trait is already implemented.

DisplayTrait.tryImplFor(Point, {
  display() {
    return `(${this.x}, ${this.y})`;
  },
});

License

MIT illuxiza