Files
traitify-ts/src/trait.ts
Julien Valverdé ec914e0ffd
Some checks failed
continuous-integration/drone/push Build is failing
TraitExpressionTraitsFn
2024-02-04 02:22:35 +01:00

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>,
)
}