Trait reimplementation work

This commit is contained in:
Julien Valverdé
2024-01-28 19:56:12 +01:00
parent eaaabeec49
commit f5ab00c34a

View File

@@ -1,117 +1,56 @@
import { AbstractClass, AbstractConstructor, Opaque } from "type-fest" import { AbstractClass, Class, Opaque } from "type-fest"
import { StaticMembers } from "./util"
/** type RemoveAbstractMembersFromImpl<
* Represents a trait that can be applied to a class. ImplWithAbstractMembers extends Class<AbstractMembers, []>,
* @template C - The abstract class type. AbstractMembers extends object,
*/
export type Trait<
C extends AbstractClass<any>
> = Opaque<
TraitApplier<C>,
"@thilawyn/thilatrait/Trait"
>
export type TraitApplierSuperTag = "@thilawyn/thilatrait/Super"
/**
* Represents the function signature for applying a trait to a parent class.
* @template C - The abstract class type.
*/
export type TraitApplier<
C extends AbstractClass<any>
> = ( > = (
(Super: Opaque<AbstractConstructor<object>, TraitApplierSuperTag>) => Opaque<C, TraitApplierSuperTag> Class<
Omit<InstanceType<ImplWithAbstractMembers>, keyof AbstractMembers>,
ConstructorParameters<ImplWithAbstractMembers>
> &
StaticMembers<ImplWithAbstractMembers>
) )
/**
* Creates a trait using the provided trait applier function. export type TraitTag = "@thilawyn/traitify-ts/Trait"
* @template C - The abstract class type.
* @param applier - The trait applier function. export type Trait<
* @returns A trait. AbstractMembers extends object,
* @example Impl extends Class<any, []>,
* Creates a trait: > = (
* ```ts Opaque<{
* const Permissible = trait(Super => { readonly AbstractMembers: AbstractMembers
* abstract class Permissible extends Super { readonly Impl: Impl
* static readonly defaultPermissions: string[] = [] }, TraitTag>
* permissions: string[] = [] )
*
* // Constructor is optional
* // If you wish to use it, make sure it takes any[] as an args array and passes it to the super call. This is necessary for inheritance to work properly. export type TraitApplierSuperTag = "@thilawyn/traitify-ts/Super"
* // Trait constructors cannot have typed arguments of their own, they only serve to run logic during object instantiation.
* constructor(...args: any[]) { export type TraitApplier<
* super(...args) AbstractMembers extends object,
* } ImplWithAbstractMembers extends Class<AbstractMembers, []>,
* } > = (
* (Super: Opaque<AbstractClass<AbstractMembers>, TraitApplierSuperTag>) => (
* return Permissible Opaque<ImplWithAbstractMembers, TraitApplierSuperTag>
* }) )
* ``` )
* Creates a generic trait:
* ```ts
* const Identifiable = <ID>() =>
* trait(Super => {
* abstract class Identifiable extends Super {
* abstract readonly id: ID
*
* equals(el: Identifiable) {
* return this.id === el.id
* }
*
* // Optional
* constructor(...args: any[]) {
* super(...args)
* }
* }
*
* return Identifiable
* })
* ```
* Creates a subtrait:
* ```ts
* const ImplementsIdentifiable = <ID>(defaultID: ID) =>
* trait(Super => {
* abstract class ImplementsIdentifiable extends extendsAndExpresses(
* Super,
* Identifiable<ID>(),
* ) {
* id: ID = defaultID
*
* // Optional
* constructor(...args: any[]) {
* super(...args)
* }
* }
*
* return ImplementsIdentifiable
* })
* ```
*/
export function trait< export function trait<
C extends AbstractClass<any> AbstractMembers extends object = {}
>( >(): (
applier: TraitApplier<C> <ImplWithAbstractMembers extends Class<AbstractMembers, []>>(
applier: TraitApplier<AbstractMembers, ImplWithAbstractMembers>
) => Trait<
AbstractMembers,
RemoveAbstractMembersFromImpl<
ImplWithAbstractMembers,
AbstractMembers
>
>
) { ) {
return applier as Trait<C> return (applier) => applier()
} }
/**
* Returns the class type of a trait.
* @template T - The trait type.
*/
export type TraitClass<T> = (
T extends Trait<infer C>
? C
: never
)
/**
* Returns the instance type of a trait.
* @template T - The trait type.
*/
export type TraitInstance<T> = (
T extends Trait<infer C>
? InstanceType<C>
: never
)