import { Fn } from "hotscript" import { AbstractClass, Class, Opaque } from "type-fest" import { StaticMembers } from "./util" import { AbstractTag } from "." type AddAbstractToImpl< Impl extends Class, Abstract extends object, > = ( Class< InstanceType & Abstract, ConstructorParameters > & StaticMembers ) type RemoveAbstractFromImpl< ImplWithAbstract extends Class, Abstract extends object, > = ( Class< Omit, keyof Abstract>, ConstructorParameters > & StaticMembers ) export type TraitTag = "@thilawyn/traitify-ts/Trait" export type Trait< Abstract extends object, Impl extends Class, > = ( Opaque<{ readonly apply: TraitApplier< Abstract, AddAbstractToImpl > }, TraitTag> ) export type TraitAbstractMembers = ( T extends Trait ? AbstractMembers : never ) export interface TraitAbstractMembersFn extends Fn { return: TraitAbstractMembers } export type TraitImplClass = ( T extends Trait ? Impl : never ) export interface TraitImplClassFn extends Fn { return: TraitImplClass } export type TraitImplInstance = ( T extends Trait ? InstanceType : never ) export interface TraitImplInstanceFn extends Fn { return: TraitImplInstance } export type TraitClass = ( T extends Trait ? AddAbstractToImpl : never ) export interface TraitClassFn extends Fn { return: TraitClass } export type TraitInstance = ( T extends Trait ? InstanceType< AddAbstractToImpl > : never ) export interface TraitInstanceFn extends Fn { return: TraitInstance } export type TraitApplierSuperTag = "@thilawyn/traitify-ts/TraitApplierSuper" export type TraitApplier< Abstract extends object, ImplWithAbstract extends Class, > = ( (Super: Opaque, TraitApplierSuperTag>) => ( Opaque ) ) export function trait< Abstract extends {}, ImplWithAbstract extends Class, >( abstract: Opaque, apply: (Super: Opaque, TraitApplierSuperTag>) => ( Opaque ), ): Trait< Abstract, RemoveAbstractFromImpl > { return { apply } as any }