npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ddd-ts/traits

v0.0.49

Published

A TypeScript typesafe library for implementing the trait pattern.

Readme

@ddd-ts/traits 👥💡

A TypeScript typesafe library for implementing the trait pattern.

Installation ⬇️

npm install @ddd-ts/traits

Usage 🚀

The @ddd-ts/traits library provides utility functions for implementing the trait pattern in TypeScript. Traits allow you to compose reusable behaviors and mix them into classes without the need for inheritance.

Importing 📥

import { Derive, Subtrait, Trait, implementsTrait } from "@ddd-ts/traits";

Creating Traits ✨

A trait is defined using the Trait function, which takes a base class and returns a new class that extends the base class with additional behavior.

const Swim = Trait(
  (base) =>
    class extends base {
      swim() {
        return 1;
      }
    }
);

const Walk = Trait(
  (base) =>
    class extends base {
      walk() {
        return 1;
      }
    }
);

Deriving Traits 🧬

To apply a trait to a class, use the Derive function. It takes the trait as an argument and returns a new class that extends the base class with the trait's behavior.

class Fish extends Derive(Swim) {}

const fish = new Fish({});

console.log(fish.swim()); // Output: 1

Overloading Trait Methods ⚙️

You can override a trait method in a derived class by defining the same method and using the super keyword to call the base implementation.

class Dog extends Derive(Swim) {
  swim() {
    return super.swim() * 0.2;
  }
}

const dog = new Dog({});

console.log(dog.swim()); // Output: 0.2

Deriving Multiple Traits 🌟

You can derive multiple traits by passing them as arguments to the Derive function.

class Dog extends Derive(Swim, Walk) {}

const dog = new Dog({});

console.log(dog.swim()); // Output: 1
console.log(dog.walk()); // Output: 1

Traits with Constructors 🏗️

If a trait requires initialization with certain properties, you can define a constructor in the trait class. When deriving a trait, you can pass the required properties to the super constructor.

const Run = Trait(
  (base) =>
    class extends base {
      speed: number;
      constructor(props: { speed: number }) {
        super(props);
        this.speed = props.speed;
      }
      run() {
        return 2 * this.speed;
      }
    }
);

class Athlete extends Derive(Run) {
  constructor() {
    super({ speed: 10 });
  }
}

const athlete = new Athlete();

console.log(athlete.run()); // Output: 20

Type Checking with Traits ✅

You can use the implementsTrait function to check if an instance implements a specific trait.

class Athlete extends Derive(Run) {
  constructor() {
    super({ speed: 10 });
  }
}

const athlete = new Athlete();

console.log(athlete instanceof Athlete); // Output: true
console.log(implementsTrait(athlete, Run)); // Output: true

Generic Traits 🎛️

Traits can also be generic, allowing you to specify additional type parameters when applying the trait.

const Eat = <E>() =>
  Trait(
    (base) =>
      class extends base {
        eat(_e: E) {}
      }
  );

class Animal extends Derive(Eat<string>()) {
  do() {
    this.eat("a");
    // @ts-expect-error should

 not allow to eat a number
    this.eat(1);
  }
}

Subtraits 🌳

Subtraits allow you to define traits that depend on other traits. The Subtrait function is used to create a subtrait, specifying the supertraits it depends on and the additional behavior it provides.

const Walk = Trait(
  (base) =>
    class extends base {
      walk() {}
    }
);

const Run = Subtrait(
  [Walk] as const, // supertrait of subtrait defined here
  (base, Props) =>
    class extends base {
      run() {
        this.walk();
        this.walk();
        this.walk();
      }
    }
);

class Athlete extends Derive(Walk, Run) {
  do() {
    this.walk();
    this.run();
  }
}

Subtraits with Props 🔧

Subtraits can also accept additional properties in their constructors. The supertraits' properties are automatically forwarded to the subtrait's constructor.

const Walk = Trait(
  (base) =>
    class extends base {
      walk() {
        return 2;
      }
    }
);

const Run = Subtrait(
  [Walk], // supertrait of subtrait defined here
  (base) =>
    class extends base {
      speed: number;
      constructor(props: { speed: number }) {
        super({});
        this.speed = props.speed;
      }
      run() {
        return this.walk() * this.speed;
      }
    }
);

class Athlete extends Derive(Walk, Run) {
  constructor() {
    super({ speed: 10 });
  }
  start() {
    return this.walk() + this.run();
  }
}

const athlete = new Athlete();

console.log(athlete.start()); // Output: 22

Forwarding Supertraits Props ↔️

When using subtraits with multiple supertraits, the properties of all supertraits are automatically forwarded to the subtrait's constructor.

const Walk = Trait(
  (base) =>
    class extends base {
      speed: number;
      constructor(props: { speed: number }) {
        super(props);
        this.speed = props.speed;
      }
      walk() {
        return this.speed * 0.1;
      }
    }
);

const Fly = Trait(
  (base) =>
    class extends base {
      wings: number;
      constructor(props: { wings: number }) {
        super({});
        this.wings = props.wings;
      }
      fly() {
        return this.wings;
      }
    }
);

const Land = Subtrait(
  [Walk, Fly], // supertraits of subtrait defined here
  (base, Props) =>
    class extends base {
      constructor(props: { weight: number } & typeof Props) {
        super(props);
      }
      land() {
        return this.walk() + this.fly() - this.weight;
      }
    }
);

class Athlete extends Derive(Walk, Fly, Land) {}

const athlete = new Athlete({ speed: 10, weight: 10, wings: 10 });

console.log(athlete.land()); // Output: 20

Limitations ⚠️

  • The ordering of supertraits is important. Subtraits must be derived in the correct order of their dependencies.

License 📄

This project is licensed under the MIT License.