import { AbstractClass, Simplify } from "type-fest" import { Trait } from "./Trait" import { TraitExpression } from "./TraitExpression" import { Extend, StaticMembers } from "./util" declare const implSuperSymbol: unique symbol type ImplSuper = ( This extends TraitBuilder< any, infer Abstract, infer StaticAbstract, infer ImplClass > ? ( AbstractClass< Simplify< Extend<[ Abstract, InstanceType, ]> > > & Simplify< Extend<[ StaticAbstract, StaticMembers, ]> > & { readonly [implSuperSymbol]: true } ) : never ) 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 >( 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 > > > & Simplify< Omit< StaticMembers, keyof StaticAbstract | typeof implSuperSymbol > > ), ) } build() { return new Trait( this.traitSuperExpression, this.traitAbstract, this.traitStaticAbstract, this.traitApply, ) } } export const trait = new TraitBuilder( new TraitExpression(TraitExpression.NullSuperclass, []), {} as object, {} as object, Super => class extends Super {} as AbstractClass, )