Traits for TypeScript
PHP-style traits with decorators. Bring horizontal code reuse, conflict resolution, and composition to TypeScript.
Simple, elegant, powerful
Define traits with decorators. Apply them to any class.
import { Trait, UsesTraits } from '@orchestr-sh/traits';
@Trait()
class Timestampable {
created_at?: Date;
updated_at?: Date;
touch(): void {
this.updated_at = new Date();
}
}
@Trait()
class SoftDeletes {
deleted_at?: Date;
softDelete(): void {
this.deleted_at = new Date();
}
}
@UsesTraits(Timestampable, SoftDeletes)
class User {
name: string = '';
// All trait methods are available
touch!: () => void;
softDelete!: () => void;
}
const user = new User();
user.touch(); // ✓ From Timestampable
user.softDelete(); // ✓ From SoftDeletesFeatures
Everything you need for flexible code composition in TypeScript.
Multiple Traits
Apply as many traits as you need to a single class. No limit on horizontal code reuse.
Conflict Resolution
Handle method conflicts with @TraitInsteadOf and @TraitAlias decorators.
Trait Composition
Traits can use other traits. Build complex behaviors from simple, reusable pieces.
Type Safety
Full TypeScript support with autocomplete and compile-time type checking.
Runtime Inspection
Inspect traits at runtime with getTraits(), hasTrait(), and getTraitInfo().
Zero Dependencies
Lightweight package with only reflect-metadata as a peer dependency.
API at a glance
Four decorators and three helper functions. That's it.
@Trait()Marks a class as a trait that can be used by other classes.
@UsesTraits(...traits)Applies one or more traits to a class. Methods and properties are copied over.
@TraitAlias(trait, original, alias)Creates an alias for a trait method to avoid naming conflicts.
@TraitInsteadOf(useTrait, method, ...insteadOf)Resolves conflicts by specifying which trait's method to use.
getTraits(target)Get all traits used by a class or instance.
hasTrait(target, trait)Check if a class uses a specific trait.
getTraitInfo(target)Get detailed trait metadata.
Elegant conflict resolution
When two traits define the same method, resolve it declaratively.
import { Trait, UsesTraits, TraitInsteadOf, TraitAlias } from '@orchestr-sh/traits';
@Trait()
class TraitA {
greet(): string { return 'Hello from A'; }
}
@Trait()
class TraitB {
greet(): string { return 'Hello from B'; }
}
@UsesTraits(TraitA, TraitB)
@TraitInsteadOf(TraitA, 'greet', TraitB) // Use TraitA's greet
@TraitAlias(TraitB, 'greet', 'greetB') // Alias TraitB's greet
class MyClass {
greet!: () => string; // From TraitA
greetB!: () => string; // From TraitB (aliased)
}Composition over inheritance
Start using PHP-style traits in your TypeScript projects today.