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