Trait reimplementation work
This commit is contained in:
157
src/trait.ts
157
src/trait.ts
@@ -1,117 +1,56 @@
|
||||
import { AbstractClass, AbstractConstructor, Opaque } from "type-fest"
|
||||
import { AbstractClass, Class, Opaque } from "type-fest"
|
||||
import { StaticMembers } from "./util"
|
||||
|
||||
|
||||
/**
|
||||
* Represents a trait that can be applied to a class.
|
||||
* @template C - The abstract class type.
|
||||
*/
|
||||
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>
|
||||
type RemoveAbstractMembersFromImpl<
|
||||
ImplWithAbstractMembers extends Class<AbstractMembers, []>,
|
||||
AbstractMembers extends object,
|
||||
> = (
|
||||
(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.
|
||||
* @template C - The abstract class type.
|
||||
* @param applier - The trait applier function.
|
||||
* @returns A trait.
|
||||
* @example
|
||||
* Creates a trait:
|
||||
* ```ts
|
||||
* const Permissible = trait(Super => {
|
||||
* abstract class Permissible extends Super {
|
||||
* static readonly defaultPermissions: string[] = []
|
||||
* 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.
|
||||
* // Trait constructors cannot have typed arguments of their own, they only serve to run logic during object instantiation.
|
||||
* constructor(...args: any[]) {
|
||||
* super(...args)
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* return Permissible
|
||||
* })
|
||||
* ```
|
||||
* 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 type TraitTag = "@thilawyn/traitify-ts/Trait"
|
||||
|
||||
export type Trait<
|
||||
AbstractMembers extends object,
|
||||
Impl extends Class<any, []>,
|
||||
> = (
|
||||
Opaque<{
|
||||
readonly AbstractMembers: AbstractMembers
|
||||
readonly Impl: Impl
|
||||
}, TraitTag>
|
||||
)
|
||||
|
||||
|
||||
export type TraitApplierSuperTag = "@thilawyn/traitify-ts/Super"
|
||||
|
||||
export type TraitApplier<
|
||||
AbstractMembers extends object,
|
||||
ImplWithAbstractMembers extends Class<AbstractMembers, []>,
|
||||
> = (
|
||||
(Super: Opaque<AbstractClass<AbstractMembers>, TraitApplierSuperTag>) => (
|
||||
Opaque<ImplWithAbstractMembers, TraitApplierSuperTag>
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
export function trait<
|
||||
C extends AbstractClass<any>
|
||||
>(
|
||||
applier: TraitApplier<C>
|
||||
AbstractMembers extends object = {}
|
||||
>(): (
|
||||
<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
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user