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