Files
traitify-ts/src/trait.ts
Julien Valverdé c1097ff2f2
All checks were successful
continuous-integration/drone/push Build is passing
Trait refactoring
2024-02-03 02:18:36 +01:00

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
}