Expresses work
This commit is contained in:
106
src/expresses.ts
106
src/expresses.ts
@@ -1,84 +1,50 @@
|
||||
import { AbstractClass, Opaque } from "type-fest"
|
||||
import { Trait, TraitApplierSuperTag } from "."
|
||||
import { ClassesInstances, ClassesStaticMembers, MergeInheritanceTree, MergeInheritanceTreeWithoutOverriding, StaticMembers, TraitsClasses } from "./util"
|
||||
import { MergeInheritanceTree, TraitsAbstractMembers } from "./util"
|
||||
|
||||
|
||||
/**
|
||||
* Extends a class with the given traits and expresses their combined functionality.
|
||||
* @template C - The abstract class type.
|
||||
* @template Traits - An array of traits.
|
||||
* @param extend - The class to extend.
|
||||
* @param traits - An array of traits to apply.
|
||||
* @returns A new class type expressing the combined functionality of the base class and traits.
|
||||
* @example
|
||||
* Extends a superclass and applies traits:
|
||||
* ```ts
|
||||
* class User extends extendsAndExpresses(Entity,
|
||||
* Identifiable<bigint>(),
|
||||
* Permissible,
|
||||
* ) {
|
||||
* readonly id: bigint
|
||||
*
|
||||
* constructor(id: bigint) {
|
||||
* super()
|
||||
* this.id = id
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function extendsAndExpresses<
|
||||
C extends AbstractClass<any>,
|
||||
Traits extends readonly Trait<any>[],
|
||||
>(
|
||||
extend: C,
|
||||
...traits: Traits
|
||||
class TraitsExpression<
|
||||
Super extends AbstractClass<any>,
|
||||
Traits extends readonly Trait<any, any>[],
|
||||
> {
|
||||
constructor(
|
||||
readonly superclass: Super,
|
||||
readonly traits: Traits,
|
||||
) {}
|
||||
|
||||
implements(): (
|
||||
MergeInheritanceTree<
|
||||
TraitsAbstractMembers<Traits>
|
||||
>
|
||||
) {
|
||||
return traits.reduce(
|
||||
(previous, trait) => trait(previous),
|
||||
extend as Opaque<C, TraitApplierSuperTag>,
|
||||
) as unknown as (
|
||||
AbstractClass<
|
||||
MergeInheritanceTreeWithoutOverriding<[
|
||||
InstanceType<C>,
|
||||
...ClassesInstances<
|
||||
TraitsClasses<Traits>
|
||||
>,
|
||||
]>,
|
||||
return {} as any
|
||||
}
|
||||
|
||||
ConstructorParameters<C>
|
||||
> &
|
||||
|
||||
MergeInheritanceTree<[
|
||||
StaticMembers<C>,
|
||||
...ClassesStaticMembers<
|
||||
TraitsClasses<Traits>
|
||||
>,
|
||||
]>
|
||||
extends() {
|
||||
return this.traits.reduce(
|
||||
(previous, trait) => trait.apply(previous),
|
||||
this.superclass as Opaque<Super, TraitApplierSuperTag>,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function extendsAndExpresses<
|
||||
Super extends AbstractClass<any>,
|
||||
Traits extends readonly Trait<any, any>[],
|
||||
>(
|
||||
superclass: Super,
|
||||
...traits: Traits
|
||||
) {
|
||||
return new TraitsExpression(superclass, traits)
|
||||
}
|
||||
|
||||
class DefaultSuperclass {}
|
||||
|
||||
/**
|
||||
* Expresses the combined functionality of multiple traits.
|
||||
* @template Traits - An array of trait.
|
||||
* @param traits - An array of trait to apply.
|
||||
* @returns A new class type expressing the combined functionality of the traits.
|
||||
* @example
|
||||
* Applies traits to a class:
|
||||
* ```ts
|
||||
* class User extends expresses(Identifiable<bigint>(), Permissible) {
|
||||
* readonly id: bigint
|
||||
*
|
||||
* constructor(id: bigint) {
|
||||
* super()
|
||||
* this.id = id
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function expresses<
|
||||
Traits extends readonly Trait<any>[],
|
||||
Traits extends readonly Trait<any, any>[],
|
||||
>(
|
||||
...traits: Traits
|
||||
) {
|
||||
return extendsAndExpresses(Object, ...traits)
|
||||
return new TraitsExpression(DefaultSuperclass, traits)
|
||||
}
|
||||
|
||||
12
src/tests.ts
12
src/tests.ts
@@ -1,4 +1,4 @@
|
||||
import { trait } from "."
|
||||
import { expresses, trait } from "."
|
||||
|
||||
|
||||
const PrintsHelloOnNew = trait()(Super =>
|
||||
@@ -10,11 +10,17 @@ const PrintsHelloOnNew = trait()(Super =>
|
||||
}
|
||||
)
|
||||
|
||||
const Identifiable = <ID>() =>
|
||||
trait<{ id: ID }>()(Super =>
|
||||
const Identifiable = <ID>() => (
|
||||
trait<{ readonly id: ID }>()(Super =>
|
||||
class Identifiable extends Super {
|
||||
equals(el: Identifiable) {
|
||||
return this.id === el.id
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
const exp = expresses(Identifiable<bigint>())
|
||||
|
||||
class User implements typeof exp.implements()
|
||||
|
||||
27
src/trait.ts
27
src/trait.ts
@@ -42,8 +42,32 @@ export type Trait<
|
||||
}, TraitTag>
|
||||
)
|
||||
|
||||
export type TraitAbstractMembers<T> = (
|
||||
T extends Trait<infer AbstractMembers, any>
|
||||
? AbstractMembers
|
||||
: never
|
||||
)
|
||||
|
||||
export type TraitApplierSuperTag = "@thilawyn/traitify-ts/Super"
|
||||
export type TraitImpl<T> = (
|
||||
T extends Trait<any, infer Impl>
|
||||
? Impl
|
||||
: never
|
||||
)
|
||||
|
||||
export type TraitClass<T> = (
|
||||
T extends Trait<infer AbstractMembers, infer Impl>
|
||||
? AddAbstractMembersToImpl<Impl, AbstractMembers>
|
||||
: never
|
||||
)
|
||||
|
||||
export type TraitInstance<T> = (
|
||||
T extends Trait<infer AbstractMembers, infer Impl>
|
||||
? InstanceType<Impl> & AbstractMembers
|
||||
: never
|
||||
)
|
||||
|
||||
|
||||
export type TraitApplierSuperTag = "@thilawyn/traitify-ts/TraitApplierSuper"
|
||||
|
||||
export type TraitApplier<
|
||||
AbstractMembers extends object,
|
||||
@@ -54,7 +78,6 @@ export type TraitApplier<
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
export function trait<
|
||||
AbstractMembers extends object = {}
|
||||
>(): (
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import { Trait, TraitClass } from ".."
|
||||
import { Trait, TraitAbstractMembers, TraitClass } from ".."
|
||||
|
||||
|
||||
/**
|
||||
* Represents an array of classes corresponding to the provided traits.
|
||||
* @template Traits - An array of traits extending Trait<any>.
|
||||
*/
|
||||
export type TraitsClasses<Traits extends readonly Trait<any>[]> = (
|
||||
export type TraitsAbstractMembers<Traits extends readonly Trait<any, any>[]> = (
|
||||
Traits extends [infer T, ...infer Rest]
|
||||
? T extends Trait<any>
|
||||
? Rest extends Trait<any>[]
|
||||
? T extends Trait<any, any>
|
||||
? Rest extends Trait<any, any>[]
|
||||
? [TraitAbstractMembers<T>, ...TraitsClasses<Rest>]
|
||||
: never
|
||||
: never
|
||||
: []
|
||||
)
|
||||
|
||||
export type TraitsClasses<Traits extends readonly Trait<any, any>[]> = (
|
||||
Traits extends [infer T, ...infer Rest]
|
||||
? T extends Trait<any, any>
|
||||
? Rest extends Trait<any, any>[]
|
||||
? [TraitClass<T>, ...TraitsClasses<Rest>]
|
||||
: never
|
||||
: never
|
||||
|
||||
Reference in New Issue
Block a user