Implementation using mixins
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
45
src/tests-inheritance.ts
Normal file
45
src/tests-inheritance.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { extendsAndExpresses, trait } from "./trait-inheritance"
|
||||||
|
|
||||||
|
|
||||||
|
const Identified = <ID>() =>
|
||||||
|
trait(Parent => {
|
||||||
|
abstract class Identified<ID> extends Parent {
|
||||||
|
abstract id: ID
|
||||||
|
|
||||||
|
equals(el: Identified<ID>) {
|
||||||
|
return this.id === el.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Identified<ID>
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
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<bigint>(),
|
||||||
|
Permissible,
|
||||||
|
] as const)
|
||||||
|
|
||||||
|
class User extends UserProto {
|
||||||
|
constructor(readonly id: bigint) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const user1 = new User(1n)
|
||||||
|
user1.equals(user1)
|
||||||
64
src/trait-inheritance.ts
Normal file
64
src/trait-inheritance.ts
Normal file
@@ -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<C> = Pick<C, keyof C>
|
||||||
|
|
||||||
|
|
||||||
|
export type Trait<C extends AbstractClass<any, any>> =
|
||||||
|
Opaque<(Parent: AbstractClass<any, any[]>) => C, "Trait">
|
||||||
|
|
||||||
|
export type GetTraitC<T> =
|
||||||
|
T extends Trait<infer C>
|
||||||
|
? C
|
||||||
|
: never
|
||||||
|
|
||||||
|
|
||||||
|
export function trait<
|
||||||
|
C extends AbstractClass<any, any[]>
|
||||||
|
>(
|
||||||
|
trait: (Parent: AbstractClass<any, any[]>) => C
|
||||||
|
) {
|
||||||
|
return trait as Trait<C>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function extendsAndExpresses<
|
||||||
|
C extends AbstractClass<any, any>,
|
||||||
|
Traits extends readonly Trait<any>[],
|
||||||
|
>(
|
||||||
|
extend: C,
|
||||||
|
traits: Traits,
|
||||||
|
) {
|
||||||
|
|
||||||
|
return extend as unknown as (
|
||||||
|
AbstractClass<
|
||||||
|
InstanceType<C> &
|
||||||
|
UnionToIntersection<
|
||||||
|
InstanceType<
|
||||||
|
GetTraitC<
|
||||||
|
Traits[number]
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>,
|
||||||
|
|
||||||
|
ConstructorParameters<C>
|
||||||
|
> &
|
||||||
|
|
||||||
|
StaticMembers<C> &
|
||||||
|
|
||||||
|
StaticMembers<
|
||||||
|
UnionToIntersection<
|
||||||
|
GetTraitC<
|
||||||
|
Traits[number]
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user