0.1.0 #1
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"
|
||||||
|
|
||||||
|
|
||||||
/**
|
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
|
|
||||||
)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user