diff --git a/src/tests-inheritance.ts b/src/tests-inheritance.ts new file mode 100644 index 0000000..0205309 --- /dev/null +++ b/src/tests-inheritance.ts @@ -0,0 +1,45 @@ +import { extendsAndExpresses, trait } from "./trait-inheritance" + + +const Identified = () => + trait(Parent => { + abstract class Identified extends Parent { + abstract id: ID + + equals(el: Identified) { + return this.id === el.id + } + } + + return Identified + }) + + +const Permissible = trait(Parent => { + abstract class Permissible extends Parent { + static readonly defaultPermissions: string[] = [] + permissions: string[] = [] + + constructor() { + super() + console.log("Permissible constructor") + } + } + + return Permissible +}) + + +const UserProto = extendsAndExpresses(class {}, [ + Identified(), + Permissible, +] as const) + +class User extends UserProto { + constructor(readonly id: bigint) { + super() + } +} + +const user1 = new User(1n) +user1.equals(user1) diff --git a/src/trait-inheritance.ts b/src/trait-inheritance.ts new file mode 100644 index 0000000..cee3cb1 --- /dev/null +++ b/src/trait-inheritance.ts @@ -0,0 +1,64 @@ +import { AbstractClass, Opaque, UnionToIntersection } from "type-fest" + + +/** + * Represents the static members of a class. + * + * @template C - The type of the class for which static members are extracted. + * @typeparam The static members of the class. + */ +export type StaticMembers = Pick + + +export type Trait> = + Opaque<(Parent: AbstractClass) => C, "Trait"> + +export type GetTraitC = + T extends Trait + ? C + : never + + +export function trait< + C extends AbstractClass +>( + trait: (Parent: AbstractClass) => C +) { + return trait as Trait +} + + +export function extendsAndExpresses< + C extends AbstractClass, + Traits extends readonly Trait[], +>( + extend: C, + traits: Traits, +) { + + return extend as unknown as ( + AbstractClass< + InstanceType & + UnionToIntersection< + InstanceType< + GetTraitC< + Traits[number] + > + > + >, + + ConstructorParameters + > & + + StaticMembers & + + StaticMembers< + UnionToIntersection< + GetTraitC< + Traits[number] + > + > + > + ) + +}