0.1.0 #1
106
src/expresses.ts
106
src/expresses.ts
@@ -1,84 +1,50 @@
|
|||||||
import { AbstractClass, Opaque } from "type-fest"
|
import { AbstractClass, Opaque } from "type-fest"
|
||||||
import { Trait, TraitApplierSuperTag } from "."
|
import { Trait, TraitApplierSuperTag } from "."
|
||||||
import { ClassesInstances, ClassesStaticMembers, MergeInheritanceTree, MergeInheritanceTreeWithoutOverriding, StaticMembers, TraitsClasses } from "./util"
|
import { MergeInheritanceTree, TraitsAbstractMembers } from "./util"
|
||||||
|
|
||||||
|
|
||||||
|
class TraitsExpression<
|
||||||
|
Super extends AbstractClass<any>,
|
||||||
|
Traits extends readonly Trait<any, any>[],
|
||||||
|
> {
|
||||||
|
constructor(
|
||||||
|
readonly superclass: Super,
|
||||||
|
readonly traits: Traits,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
implements(): (
|
||||||
|
MergeInheritanceTree<
|
||||||
|
TraitsAbstractMembers<Traits>
|
||||||
|
>
|
||||||
|
) {
|
||||||
|
return {} as any
|
||||||
|
}
|
||||||
|
|
||||||
|
extends() {
|
||||||
|
return this.traits.reduce(
|
||||||
|
(previous, trait) => trait.apply(previous),
|
||||||
|
this.superclass as Opaque<Super, TraitApplierSuperTag>,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<
|
export function extendsAndExpresses<
|
||||||
C extends AbstractClass<any>,
|
Super extends AbstractClass<any>,
|
||||||
Traits extends readonly Trait<any>[],
|
Traits extends readonly Trait<any, any>[],
|
||||||
>(
|
>(
|
||||||
extend: C,
|
superclass: Super,
|
||||||
...traits: Traits
|
...traits: Traits
|
||||||
) {
|
) {
|
||||||
return traits.reduce(
|
return new TraitsExpression(superclass, traits)
|
||||||
(previous, trait) => trait(previous),
|
|
||||||
extend as Opaque<C, TraitApplierSuperTag>,
|
|
||||||
) as unknown as (
|
|
||||||
AbstractClass<
|
|
||||||
MergeInheritanceTreeWithoutOverriding<[
|
|
||||||
InstanceType<C>,
|
|
||||||
...ClassesInstances<
|
|
||||||
TraitsClasses<Traits>
|
|
||||||
>,
|
|
||||||
]>,
|
|
||||||
|
|
||||||
ConstructorParameters<C>
|
|
||||||
> &
|
|
||||||
|
|
||||||
MergeInheritanceTree<[
|
|
||||||
StaticMembers<C>,
|
|
||||||
...ClassesStaticMembers<
|
|
||||||
TraitsClasses<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<
|
export function expresses<
|
||||||
Traits extends readonly Trait<any>[],
|
Traits extends readonly Trait<any, any>[],
|
||||||
>(
|
>(
|
||||||
...traits: Traits
|
...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 =>
|
const PrintsHelloOnNew = trait()(Super =>
|
||||||
@@ -10,11 +10,17 @@ const PrintsHelloOnNew = trait()(Super =>
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const Identifiable = <ID>() =>
|
const Identifiable = <ID>() => (
|
||||||
trait<{ id: ID }>()(Super =>
|
trait<{ readonly id: ID }>()(Super =>
|
||||||
class Identifiable extends Super {
|
class Identifiable extends Super {
|
||||||
equals(el: Identifiable) {
|
equals(el: Identifiable) {
|
||||||
return this.id === el.id
|
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>
|
}, 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<
|
export type TraitApplier<
|
||||||
AbstractMembers extends object,
|
AbstractMembers extends object,
|
||||||
@@ -54,7 +78,6 @@ export type TraitApplier<
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
export function trait<
|
export function trait<
|
||||||
AbstractMembers extends object = {}
|
AbstractMembers extends object = {}
|
||||||
>(): (
|
>(): (
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
import { Trait, TraitClass } from ".."
|
import { Trait, TraitAbstractMembers, TraitClass } from ".."
|
||||||
|
|
||||||
|
|
||||||
/**
|
export type TraitsAbstractMembers<Traits extends readonly Trait<any, any>[]> = (
|
||||||
* 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>[]> = (
|
|
||||||
Traits extends [infer T, ...infer Rest]
|
Traits extends [infer T, ...infer Rest]
|
||||||
? T extends Trait<any>
|
? T extends Trait<any, any>
|
||||||
? Rest extends Trait<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>]
|
? [TraitClass<T>, ...TraitsClasses<Rest>]
|
||||||
: never
|
: never
|
||||||
: never
|
: never
|
||||||
|
|||||||
Reference in New Issue
Block a user