0.1.0 #1

Merged
Thilawyn merged 65 commits from next into master 2024-02-06 03:15:40 +01:00
4 changed files with 84 additions and 83 deletions
Showing only changes of commit 8b01a13d7c - Show all commits

View File

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

View File

@@ -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()

View File

@@ -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 = {}
>(): ( >(): (

View File

@@ -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