diff --git a/src/expresses.ts b/src/expresses.ts index 5784e56..d8dbe4c 100644 --- a/src/expresses.ts +++ b/src/expresses.ts @@ -1,84 +1,50 @@ import { AbstractClass, Opaque } from "type-fest" import { Trait, TraitApplierSuperTag } from "." -import { ClassesInstances, ClassesStaticMembers, MergeInheritanceTree, MergeInheritanceTreeWithoutOverriding, StaticMembers, TraitsClasses } from "./util" +import { MergeInheritanceTree, TraitsAbstractMembers } from "./util" + + +class TraitsExpression< + Super extends AbstractClass, + Traits extends readonly Trait[], +> { + constructor( + readonly superclass: Super, + readonly traits: Traits, + ) {} + + implements(): ( + MergeInheritanceTree< + TraitsAbstractMembers + > + ) { + return {} as any + } + + extends() { + return this.traits.reduce( + (previous, trait) => trait.apply(previous), + this.superclass as Opaque, + ) + } +} -/** - * 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[], + Super extends AbstractClass, + Traits extends readonly Trait[], >( - extend: C, - ...traits: Traits + superclass: Super, + ...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 - >, - ]> - ) + return new TraitsExpression(superclass, traits) } -/** - * 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 - * } - * } - * ``` - */ +class DefaultSuperclass {} + export function expresses< - Traits extends readonly Trait[], + Traits extends readonly Trait[], >( ...traits: Traits ) { - return extendsAndExpresses(Object, ...traits) + return new TraitsExpression(DefaultSuperclass, traits) } diff --git a/src/tests.ts b/src/tests.ts index 59df546..9b096a8 100644 --- a/src/tests.ts +++ b/src/tests.ts @@ -1,4 +1,4 @@ -import { trait } from "." +import { expresses, trait } from "." const PrintsHelloOnNew = trait()(Super => @@ -10,11 +10,17 @@ const PrintsHelloOnNew = trait()(Super => } ) -const Identifiable = () => - trait<{ id: ID }>()(Super => +const Identifiable = () => ( + trait<{ readonly id: ID }>()(Super => class Identifiable extends Super { equals(el: Identifiable) { return this.id === el.id } } ) +) + + +const exp = expresses(Identifiable()) + +class User implements typeof exp.implements() diff --git a/src/trait.ts b/src/trait.ts index fe1898a..6736755 100644 --- a/src/trait.ts +++ b/src/trait.ts @@ -42,8 +42,32 @@ export type Trait< }, TraitTag> ) +export type TraitAbstractMembers = ( + T extends Trait + ? AbstractMembers + : never +) -export type TraitApplierSuperTag = "@thilawyn/traitify-ts/Super" +export type TraitImpl = ( + T extends Trait + ? Impl + : never +) + +export type TraitClass = ( + T extends Trait + ? AddAbstractMembersToImpl + : never +) + +export type TraitInstance = ( + T extends Trait + ? InstanceType & AbstractMembers + : never +) + + +export type TraitApplierSuperTag = "@thilawyn/traitify-ts/TraitApplierSuper" export type TraitApplier< AbstractMembers extends object, @@ -54,7 +78,6 @@ export type TraitApplier< ) ) - export function trait< AbstractMembers extends object = {} >(): ( diff --git a/src/util/trait.ts b/src/util/trait.ts index 149599d..83153cd 100644 --- a/src/util/trait.ts +++ b/src/util/trait.ts @@ -1,14 +1,20 @@ -import { Trait, TraitClass } from ".." +import { Trait, TraitAbstractMembers, TraitClass } from ".." -/** - * Represents an array of classes corresponding to the provided traits. - * @template Traits - An array of traits extending Trait. - */ -export type TraitsClasses[]> = ( +export type TraitsAbstractMembers[]> = ( Traits extends [infer T, ...infer Rest] - ? T extends Trait - ? Rest extends Trait[] + ? T extends Trait + ? Rest extends Trait[] + ? [TraitAbstractMembers, ...TraitsClasses] + : never + : never + : [] +) + +export type TraitsClasses[]> = ( + Traits extends [infer T, ...infer Rest] + ? T extends Trait + ? Rest extends Trait[] ? [TraitClass, ...TraitsClasses] : never : never