makeLinkClass
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Julien Valverdé
2023-12-25 01:46:38 +01:00
parent d8e509f540
commit a32c9c70f5
2 changed files with 108 additions and 69 deletions

View File

@@ -1,72 +1,85 @@
import { AbstractClass, Class, UnionToIntersection } from "type-fest"
import { StaticMembers, copyProperties, flattenClass, getInheritanceHierarchy } from "./util/class"
import { StaticMembers, copyProperties, getInheritanceHierarchy } from "./util/class"
/**
* Represents a trait that can be used to define common behavior
* for classes and abstract classes.
* @typeParam T - The type of the trait.
*/
export type Trait<T> =
AbstractClass<T, []>
// export function applyTrait<
// C extends Class<any, any> | AbstractClass<any, any>,
// TraitC extends Trait<any>,
// >(
// class_: C,
// trait: TraitC,
// ) {
// copyClassProperties(trait, class_)
// return class_ as (
// (C extends Class<any, any>
// ? Class<
// InstanceType<C> & InstanceType<TraitC>,
// ConstructorParameters<C>
// >
// : AbstractClass<
// InstanceType<C> & InstanceType<TraitC>,
// ConstructorParameters<C>
// >
// ) &
// StaticMembers<C> &
// StaticMembers<TraitC>
// )
// }
export const extendAndApplyTraits = <
C extends Class<any, any> | AbstractClass<any, any>,
Traits extends readonly Trait<any>[],
>(
classToExtend: C,
traits: Traits,
) =>
traits.reduce((class_, trait) => {
copyProperties(flattenClass(trait), class_)
return class_
}, class extends classToExtend {}) as (
AbstractClass<
InstanceType<C> &
UnionToIntersection<
InstanceType<Traits[number]>
>,
ConstructorParameters<C>
> &
StaticMembers<
C &
UnionToIntersection<
Traits[number]
>
>
)
/**
* Creates a link class that expresses the given traits.
* @param traits - An array of traits to be expressed by the link class.
* @returns A dynamically created class that expresses the given traits.
* @typeParam Traits - An array of traits that the link class expresses.
*/
export function expresses<
Traits extends readonly Trait<any>[]
>(
...traits: Traits
) {
const class_ = class {}
return makeLinkClass(traits)
}
/**
* Creates a link class that extends a base class and expresses the given traits.
* @param extend - The base class or abstract class to extend.
* @param traits - An array of traits to be expressed by the link class.
* @returns A dynamically created class that extends the given base class and expresses the given traits.
* @typeParam C - The type of the base class to extend.
* @typeParam Traits - An array of traits that the link class expresses.
*/
export function extendsAndExpresses<
C extends Class<any, any>
| AbstractClass<any, any>,
Traits extends readonly Trait<any>[],
>(
extend: C,
...traits: Traits
) {
return makeLinkClass(traits, extend)
}
/**
* Creates a link class that expresses the given traits and optionally extends a base class.
* @param traits - An array of traits to be expressed by the link class.
* @param extend - The base class or abstract class to extend (optional).
* @returns A dynamically created class that expresses the given traits and extends the base class.
* @typeParam Traits - An array of traits that the link class expresses.
* @typeParam C - The type of the base class to extend (optional).
*/
export function makeLinkClass<
Traits extends readonly Trait<any>[],
C extends Class<any, any>
| AbstractClass<any, any>
| undefined = undefined,
>(
traits: Traits,
extend?: C,
) {
const class_ = extend
? class extends extend {
constructor(...args: any[]) {
super(...args)
traits.forEach(trait => {
trait.prototype.initializer?.call(this)
})
}
}
: class {
constructor() {
traits.forEach(trait => {
trait.prototype.initializer?.call(this)
})
}
}
traits.forEach(trait => {
getInheritanceHierarchy(trait).forEach(current => {
@@ -80,13 +93,29 @@ export function expresses<
})
return class_ as unknown as (
Trait<
UnionToIntersection<
InstanceType<
Traits[number]
(C extends Class<any, any> | AbstractClass<any, any>
? (
AbstractClass<
InstanceType<C> &
UnionToIntersection<
InstanceType<
Traits[number]
>
>,
ConstructorParameters<C>
> &
StaticMembers<C>
)
: Trait<
UnionToIntersection<
InstanceType<
Traits[number]
>
>
>
> &
) &
StaticMembers<
UnionToIntersection<