import { AbstractClass, Opaque } from "type-fest" import { Trait, TraitApplierSuperTag } from "." import { ClassesInstances, ClassesStaticMembers, MergeInheritanceTree, MergeInheritanceTreeWithoutOverriding, StaticMembers, TraitsClasses } from "./util" /** * Extends a class with the given traits and expresses their combined functionality. * @template C - The abstract class type. * @template Traits - An array of traits. * @param extend - The class to extend. * @param traits - An array of traits to apply. * @returns A new class type expressing the combined functionality of the base class and traits. * @example * Extends a superclass and applies traits: * ```ts * class User extends extendsAndExpresses(Entity, * Identifiable(), * Permissible, * ) { * readonly id: bigint * * constructor(id: bigint) { * super() * this.id = id * } * } * ``` */ export function extendsAndExpresses< C extends AbstractClass, Traits extends readonly Trait[], >( extend: C, ...traits: Traits ) { return traits.reduce( (previous, trait) => trait(previous), extend as Opaque, ) as unknown as ( AbstractClass< MergeInheritanceTreeWithoutOverriding<[ InstanceType, ...ClassesInstances< TraitsClasses >, ]>, ConstructorParameters > & MergeInheritanceTree<[ StaticMembers, ...ClassesStaticMembers< TraitsClasses >, ]> ) } /** * Expresses the combined functionality of multiple traits. * @template Traits - An array of trait. * @param traits - An array of trait to apply. * @returns A new class type expressing the combined functionality of the traits. * @example * Applies traits to a class: * ```ts * class User extends expresses(Identifiable(), Permissible) { * readonly id: bigint * * constructor(id: bigint) { * super() * this.id = id * } * } * ``` */ export function expresses< Traits extends readonly Trait[], >( ...traits: Traits ) { return extendsAndExpresses(Object, ...traits) }