122 lines
3.3 KiB
TypeScript
122 lines
3.3 KiB
TypeScript
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> = (
|
|
This extends TraitBuilder<
|
|
any,
|
|
infer Abstract,
|
|
infer StaticAbstract,
|
|
infer ImplClass
|
|
>
|
|
? (
|
|
AbstractClass<
|
|
Simplify<
|
|
Extend<[
|
|
Abstract,
|
|
InstanceType<ImplClass>,
|
|
]>
|
|
>
|
|
> &
|
|
|
|
Simplify<
|
|
Extend<[
|
|
StaticAbstract,
|
|
StaticMembers<ImplClass>,
|
|
]>
|
|
> &
|
|
{ readonly [implSuperSymbol]: true }
|
|
)
|
|
: never
|
|
)
|
|
|
|
|
|
export class TraitBuilder<
|
|
SuperExpression extends TraitExpression<
|
|
typeof TraitExpression.NullSuperclass,
|
|
Trait<any, any, any, any>[]
|
|
>,
|
|
Abstract extends object,
|
|
StaticAbstract extends object,
|
|
ImplClass extends AbstractClass<object, []>,
|
|
> {
|
|
constructor(
|
|
private readonly traitSuperExpression: SuperExpression,
|
|
private readonly traitAbstract: Abstract,
|
|
private readonly traitStaticAbstract: StaticAbstract,
|
|
private readonly traitApply: (Super: AbstractClass<object>) => ImplClass,
|
|
) {}
|
|
|
|
abstract<A extends Abstract>(
|
|
_: (Super: AbstractClass<Abstract>) => AbstractClass<A, []>
|
|
) {
|
|
return new TraitBuilder(
|
|
this.traitSuperExpression,
|
|
{} as Simplify<A>,
|
|
this.traitStaticAbstract,
|
|
this.traitApply,
|
|
)
|
|
}
|
|
|
|
staticAbstract<A extends StaticAbstract>(
|
|
_: (Super: AbstractClass<StaticAbstract>) => AbstractClass<A, []>
|
|
) {
|
|
return new TraitBuilder(
|
|
this.traitSuperExpression,
|
|
this.traitAbstract,
|
|
{} as Simplify<A>,
|
|
this.traitApply,
|
|
)
|
|
}
|
|
|
|
implement<
|
|
ImplClassWithAbstract extends ImplSuper<typeof this>
|
|
>(
|
|
apply: (Super: ImplSuper<typeof this>) => ImplClassWithAbstract
|
|
) {
|
|
return new TraitBuilder(
|
|
this.traitSuperExpression,
|
|
this.traitAbstract,
|
|
this.traitStaticAbstract,
|
|
|
|
apply as unknown as (Super: AbstractClass<object>) => (
|
|
AbstractClass<
|
|
Simplify<
|
|
Omit<
|
|
InstanceType<ImplClassWithAbstract>,
|
|
keyof Abstract
|
|
>
|
|
>
|
|
> &
|
|
|
|
Simplify<
|
|
Omit<
|
|
StaticMembers<ImplClassWithAbstract>,
|
|
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<object>,
|
|
)
|