import { AbstractClass, Simplify } from "type-fest" import { Trait, Traits } from "./Trait" import { TraitExpression } from "./TraitExpression" import { ExtendPlain, StaticMembers } from "./util" type ImplSuper< SuperExpression extends TraitExpression< typeof TraitExpression.NullSuperclass, Trait[] >, Abstract extends object, StaticAbstract extends object, > = ( AbstractClass< ExtendPlain<[ ...Traits.MapImplInstance< TraitExpression.Traits >, Abstract, ]> > & ExtendPlain<[ ...Traits.MapImplStaticMembers< TraitExpression.Traits >, StaticAbstract, ]> & { readonly _tag: "@thilawyn/traitify-ts/Super" } // TODO: replace with unique symbol? ) export class TraitBuilder< SuperExpression extends TraitExpression< typeof TraitExpression.NullSuperclass, Trait[] >, Abstract extends object, StaticAbstract extends object, ImplClass extends AbstractClass, > { constructor( private readonly traitSuperExpression: SuperExpression, private readonly traitAbstract: Abstract, private readonly traitStaticAbstract: StaticAbstract, private readonly traitApply: (Super: AbstractClass) => ImplClass, ) {} abstract( _: (Super: AbstractClass) => AbstractClass ) { return new TraitBuilder( this.traitSuperExpression, {} as Simplify, this.traitStaticAbstract, this.traitApply, ) } staticAbstract( _: (Super: AbstractClass) => AbstractClass ) { return new TraitBuilder( this.traitSuperExpression, this.traitAbstract, {} as Simplify, this.traitApply, ) } implement< ImplClassWithAbstract extends ImplSuper< // TODO: use This instead? SuperExpression, Abstract, StaticAbstract > >( apply: ( Super: ImplSuper ) => ImplClassWithAbstract ) { return new TraitBuilder( this.traitSuperExpression, this.traitAbstract, this.traitStaticAbstract, apply as unknown as (Super: AbstractClass) => ( AbstractClass< Simplify< Omit< InstanceType, keyof Abstract > >, ConstructorParameters > & Simplify< Omit< StaticMembers, keyof StaticAbstract | "_tag" > > ), ) } build() { return new Trait( this.traitSuperExpression, this.traitAbstract, this.traitStaticAbstract, this.traitApply, ) } } export const trait = new TraitBuilder( new TraitExpression(TraitExpression.NullSuperclass, []), {}, {}, Super => class extends Super {}, )