Files
traitify-ts/src/Trait.ts
Julien Valverdé c1c3c07524
All checks were successful
continuous-integration/drone/push Build is passing
0.1.3 (#3)
Co-authored-by: Julien Valverdé <julien.valverde@mailo.com>
Reviewed-on: https://git.jvalver.de/Thilawyn/traitify-ts/pulls/3
2024-02-08 20:01:16 +01:00

158 lines
4.5 KiB
TypeScript

import { Fn, Pipe, Tuples } from "hotscript"
import { AbstractClass, Class, Opaque } from "type-fest"
import { TraitExpression, emptyTraitExpression } from "./TraitExpression"
import { AbstractTag } from "./abstract"
import { ExtendFn, SimplifyFn, StaticMembers, StaticMembersFn } from "./util"
export type TraitApplierSuperTag = "@thilawyn/traitify-ts/TraitApplierSuper"
export type AddAbstractToImplClass<
ImplClass extends Class<{}, []>,
Abstract extends {},
> = (
Class<
Abstract & InstanceType<ImplClass>,
ConstructorParameters<ImplClass>
> &
StaticMembers<ImplClass>
)
export type RemoveAbstractFromImplClass<
ImplClassWithAbstract extends Class<Abstract, []> & { _tag: TraitApplierSuperTag },
Abstract extends {},
> = (
Class<
Omit<InstanceType<ImplClassWithAbstract>, keyof Abstract>,
ConstructorParameters<ImplClassWithAbstract>
> &
Omit<StaticMembers<ImplClassWithAbstract>, "_tag">
)
export class Trait<
Supertraits extends TraitExpression<typeof TraitExpression.NullSuperclass, Trait<any, any, any>[], Trait<any, any, any>[]>,
Abstract extends {},
ImplClass extends Class<{}, []>,
> {
constructor(
readonly supertraits: Supertraits,
readonly abstract: Abstract,
readonly apply: (Super: AbstractClass<{}>) => ImplClass,
) {}
}
export namespace Trait {
export type OwnSupertraits<T> = (
T extends Trait<infer Supertraits, any, any>
? Supertraits
: never
)
export interface OwnSupertraitsFn extends Fn {
return: Trait.OwnSupertraits<this["arg0"]>
}
export type OwnAbstract<T> = (
T extends Trait<any, infer Abstract, any>
? Abstract
: never
)
export interface OwnAbstractFn extends Fn {
return: Trait.OwnAbstract<this["arg0"]>
}
export type OwnImplClass<T> = (
T extends Trait<any, any, infer ImplClass>
? ImplClass
: never
)
export interface OwnImplClassFn extends Fn {
return: Trait.OwnImplClass<this["arg0"]>
}
export type OwnImplInstance<T> = (
T extends Trait<any, any, infer ImplClass>
? InstanceType<ImplClass>
: never
)
export interface OwnImplInstanceFn extends Fn {
return: Trait.OwnImplInstance<this["arg0"]>
}
export type OwnClass<T> = (
T extends Trait<any, infer Abstract, infer ImplClass>
? AddAbstractToImplClass<ImplClass, Abstract>
: never
)
export interface OwnClassFn extends Fn {
return: Trait.OwnClass<this["arg0"]>
}
export type OwnInstance<T> = (
T extends Trait<any, infer Abstract, infer ImplClass>
? InstanceType<
AddAbstractToImplClass<ImplClass, Abstract>
>
: never
)
export interface OwnInstanceFn extends Fn {
return: Trait.OwnInstance<this["arg0"]>
}
export type Supertraits<T> = (
T extends Trait<infer Supertraits, any, any>
? TraitExpression.AllTraits<Supertraits>
: never
)
export interface SupertraitsFn extends Fn {
return: Trait.Supertraits<this["arg0"]>
}
export type Class<T> = (
AbstractClass<
Trait.Instance<T>,
any[]
> &
Pipe<T, [
Trait.SupertraitsFn,
Tuples.Append<T>,
Tuples.Map<Trait.OwnClassFn>,
Tuples.Map<StaticMembersFn>,
ExtendFn,
SimplifyFn,
]>
)
export interface ClassFn extends Fn {
return: Trait.Class<this["arg0"]>
}
export type Instance<T> = (
Pipe<T, [
Trait.SupertraitsFn,
Tuples.Append<T>,
Tuples.Map<Trait.OwnInstanceFn>,
ExtendFn,
SimplifyFn,
]>
)
export interface InstanceFn extends Fn {
return: Trait.Instance<this["arg0"]>
}
}
export function trait<
Abstract extends {},
ImplClassWithAbstract extends Class<Abstract, []> & { _tag: TraitApplierSuperTag },
>(
abstract: Opaque<Abstract, AbstractTag>,
apply: (Super: AbstractClass<Abstract> & { _tag: TraitApplierSuperTag }) => ImplClassWithAbstract,
) {
return new Trait(
emptyTraitExpression,
abstract as Abstract,
apply as any as (Super: AbstractClass<{}>) => RemoveAbstractFromImplClass<ImplClassWithAbstract, Abstract>,
)
}