113 lines
3.4 KiB
TypeScript
113 lines
3.4 KiB
TypeScript
import { Call, Fn } from "hotscript"
|
|
import { AbstractClass, Class, Opaque } from "type-fest"
|
|
import { AbstractTag, TraitExpression, TraitExpressionAbstractFn, TraitExpressionNullSuperclass, TraitExpressionTraitsFn, emptyTraitExpression } from "."
|
|
import { ExtendFn, StaticMembers } from "./util"
|
|
|
|
|
|
type AddAbstractToImplClass<
|
|
ImplClass extends Class<{}, []>,
|
|
Abstract extends {},
|
|
> = (
|
|
Class<
|
|
InstanceType<ImplClass> & Abstract,
|
|
ConstructorParameters<ImplClass>
|
|
> &
|
|
StaticMembers<ImplClass>
|
|
)
|
|
|
|
type RemoveAbstractFromImplClass<
|
|
ImplClassWithAbstract extends Class<Abstract, []>,
|
|
Abstract extends {},
|
|
> = (
|
|
Class<
|
|
Omit<InstanceType<ImplClassWithAbstract>, keyof Abstract>,
|
|
ConstructorParameters<ImplClassWithAbstract>
|
|
> &
|
|
StaticMembers<ImplClassWithAbstract>
|
|
)
|
|
|
|
|
|
export class Trait<
|
|
Super extends TraitExpression<typeof TraitExpressionNullSuperclass, any>,
|
|
Abstract extends {},
|
|
ImplClass extends Class<{}, []>,
|
|
> {
|
|
constructor(
|
|
readonly superExpression: Super,
|
|
readonly abstract: Abstract,
|
|
readonly apply: (Super: AbstractClass<{}>) => ImplClass,
|
|
) {}
|
|
}
|
|
|
|
export interface TraitOwnAbstractFn extends Fn {
|
|
return: this["arg0"] extends Trait<any, infer Abstract, any>
|
|
? Abstract
|
|
: never
|
|
}
|
|
export type TraitOwnAbstract<T> = Call<TraitOwnAbstractFn, T>
|
|
|
|
export interface TraitOwnImplClassFn extends Fn {
|
|
return: this["arg0"] extends Trait<any, any, infer ImplClass>
|
|
? ImplClass
|
|
: never
|
|
}
|
|
export type TraitOwnImplClass<T> = Call<TraitOwnImplClassFn, T>
|
|
|
|
export interface TraitOwnImplInstanceFn extends Fn {
|
|
return: this["arg0"] extends Trait<any, any, infer ImplClass>
|
|
? InstanceType<ImplClass>
|
|
: never
|
|
}
|
|
export type TraitOwnImplInstance<T> = Call<TraitOwnImplInstanceFn, T>
|
|
|
|
export interface TraitOwnClassFn extends Fn {
|
|
return: this["arg0"] extends Trait<any, infer Abstract, infer ImplClass>
|
|
? AddAbstractToImplClass<ImplClass, Abstract>
|
|
: never
|
|
}
|
|
export type TraitOwnClass<T> = Call<TraitOwnClassFn, T>
|
|
|
|
export interface TraitOwnInstanceFn extends Fn {
|
|
return: this["arg0"] extends Trait<any, infer Abstract, infer ImplClass>
|
|
? InstanceType<
|
|
AddAbstractToImplClass<ImplClass, Abstract>
|
|
>
|
|
: never
|
|
}
|
|
export type TraitOwnInstance<T> = Call<TraitOwnInstanceFn, T>
|
|
|
|
|
|
export interface TraitSupertraitsFn extends Fn {
|
|
return: this["arg0"] extends Trait<infer Super, any, any>
|
|
? Call<TraitExpressionTraitsFn, Super>
|
|
: never
|
|
}
|
|
|
|
export interface TraitAbstractFn extends Fn {
|
|
return: this["arg0"] extends Trait<infer Super, infer Abstract, any>
|
|
? Call<ExtendFn, [
|
|
...Call<TraitExpressionAbstractFn, Super>,
|
|
Abstract,
|
|
]>
|
|
: never
|
|
}
|
|
|
|
|
|
export type TraitApplierSuperTag = "@thilawyn/traitify-ts/TraitApplierSuper"
|
|
|
|
export function trait<
|
|
Abstract extends {},
|
|
ImplClassWithAbstract extends Class<Abstract, []>,
|
|
>(
|
|
abstract: Opaque<Abstract, AbstractTag>,
|
|
apply: (Super: Opaque<AbstractClass<Abstract>, TraitApplierSuperTag>) => (
|
|
Opaque<ImplClassWithAbstract, TraitApplierSuperTag>
|
|
),
|
|
) {
|
|
return new Trait(
|
|
emptyTraitExpression,
|
|
abstract as Abstract,
|
|
apply as any as (Super: AbstractClass<{}>) => RemoveAbstractFromImplClass<ImplClassWithAbstract, Abstract>,
|
|
)
|
|
}
|