import { AbstractClass, Class } from "type-fest" import { Trait } from "./Trait" import { TraitExpression } from "./TraitExpression" import { StaticMembers } from "./util" export type TraitApplierSuperTag = "@thilawyn/traitify-ts/Super" export type RemoveAbstractFromImplClass< ImplClassWithAbstract extends ( Class & StaticAbstract & { _tag: TraitApplierSuperTag } ), Abstract extends object, StaticAbstract extends object, > = ( Class< Omit, keyof Abstract>, ConstructorParameters > & Omit, keyof StaticAbstract | "_tag"> ) export class TraitBuilder< SuperExpression extends TraitExpression< typeof TraitExpression.NullSuperclass, Trait[] >, Abstract extends object, StaticAbstract extends object, ImplClass extends Class, > { constructor( private readonly traitSuperExpression: SuperExpression, private readonly traitAbstract: Abstract, private readonly traitStaticAbstract: StaticAbstract, private readonly traitApply: (Super: AbstractClass) => ImplClass, ) {} abstract() { return new TraitBuilder( this.traitSuperExpression, {} as A, this.traitStaticAbstract, this.traitApply, ) } staticAbstract() { return new TraitBuilder( this.traitSuperExpression, this.traitAbstract, {} as A, this.traitApply, ) } implement< ImplClassWithAbstract extends ( Class & StaticAbstract & { _tag: TraitApplierSuperTag } ) >( apply: ( Super: ( AbstractClass & StaticAbstract & { _tag: TraitApplierSuperTag } ) ) => ImplClassWithAbstract ) { return new TraitBuilder( this.traitSuperExpression, this.traitAbstract, this.traitStaticAbstract, apply as unknown as (Super: AbstractClass) => RemoveAbstractFromImplClass, ) } 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 {}, )