Moved old code to legacy/
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:
82
src/index.ts
82
src/index.ts
@@ -1 +1,81 @@
|
||||
export * from "./trait"
|
||||
import { AbstractClass, AbstractConstructor, 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>
|
||||
> = Opaque<
|
||||
TraitApplier<C>,
|
||||
"thilatrait/Trait"
|
||||
>
|
||||
|
||||
export type TraitApplier<
|
||||
C extends AbstractClass<any>
|
||||
> =
|
||||
(Parent: AbstractConstructor<any>) => C
|
||||
|
||||
export type UnwrapTraitC<T> =
|
||||
T extends Trait<infer C>
|
||||
? C
|
||||
: never
|
||||
|
||||
|
||||
export function trait<
|
||||
C extends AbstractClass<any>
|
||||
>(
|
||||
applier: TraitApplier<C>
|
||||
) {
|
||||
return applier as Trait<C>
|
||||
}
|
||||
|
||||
|
||||
export function extendsAndExpresses<
|
||||
C extends AbstractClass<any>,
|
||||
Traits extends readonly Trait<any>[],
|
||||
>(
|
||||
extend: C,
|
||||
traits: Traits,
|
||||
) {
|
||||
return traits.reduce(
|
||||
(previous, trait) => trait(previous),
|
||||
extend,
|
||||
) as (
|
||||
AbstractClass<
|
||||
InstanceType<C> &
|
||||
UnionToIntersection<
|
||||
InstanceType<
|
||||
UnwrapTraitC<
|
||||
Traits[number]
|
||||
>
|
||||
>
|
||||
>,
|
||||
|
||||
ConstructorParameters<C>
|
||||
> &
|
||||
|
||||
StaticMembers<C> &
|
||||
StaticMembers<
|
||||
UnionToIntersection<
|
||||
UnwrapTraitC<
|
||||
Traits[number]
|
||||
>
|
||||
>
|
||||
>
|
||||
)
|
||||
}
|
||||
|
||||
export function expresses<
|
||||
Traits extends readonly Trait<any>[],
|
||||
>(
|
||||
...traits: Traits
|
||||
) {
|
||||
return extendsAndExpresses(Object, traits)
|
||||
}
|
||||
|
||||
74
src/legacy/tests.ts
Normal file
74
src/legacy/tests.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import { AbstractClass } from "type-fest"
|
||||
import { expresses } from "./trait"
|
||||
|
||||
|
||||
function inspectClass(class_: AbstractClass<any, any>) {
|
||||
Object.getOwnPropertyNames(class_).forEach(name => {
|
||||
console.log(
|
||||
"[static]",
|
||||
name,
|
||||
Object.getOwnPropertyDescriptor(class_, name)
|
||||
)
|
||||
})
|
||||
|
||||
Object.getOwnPropertyNames(class_.prototype).forEach(name => {
|
||||
console.log(
|
||||
"[prototype]",
|
||||
name,
|
||||
Object.getOwnPropertyDescriptor(class_.prototype, name)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
abstract class Identified<ID> {
|
||||
abstract id: ID
|
||||
|
||||
equals(el: Identified<ID>) {
|
||||
return this.id === el.id
|
||||
}
|
||||
|
||||
// initializer() {
|
||||
// console.log("Identified initializer")
|
||||
// }
|
||||
}
|
||||
|
||||
class ImplementsIdentifiable<ID> extends Identified<ID> {
|
||||
id!: ID
|
||||
}
|
||||
|
||||
|
||||
abstract class Permissible {
|
||||
static readonly defaultPermissions: string[] = []
|
||||
permissions: string[] = []
|
||||
// permissions!: string[]
|
||||
|
||||
constructor() {
|
||||
console.log("Permissible constructor")
|
||||
}
|
||||
|
||||
initializer() {
|
||||
console.log("Permissible initializer")
|
||||
this.permissions = []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class User extends expresses(
|
||||
Identified as typeof Identified<bigint>,
|
||||
// Identified<string>,
|
||||
Permissible,
|
||||
) {
|
||||
readonly id: bigint
|
||||
|
||||
constructor(id: bigint) {
|
||||
super()
|
||||
this.id = id
|
||||
}
|
||||
}
|
||||
|
||||
const user1 = new User(BigInt(1))
|
||||
const user2 = new User(BigInt(2))
|
||||
|
||||
console.log(user1)
|
||||
console.log(user1.equals(user2))
|
||||
@@ -1,62 +0,0 @@
|
||||
import { expresses, trait } from "./trait-inheritance"
|
||||
|
||||
|
||||
const Identifiable = <ID>() =>
|
||||
trait(Parent => {
|
||||
abstract class Identified extends Parent {
|
||||
abstract id: ID
|
||||
|
||||
equals(el: Identified) {
|
||||
return this.id === el.id
|
||||
}
|
||||
|
||||
constructor(...args: any[]) {
|
||||
super(...args)
|
||||
console.log("Identified constructor")
|
||||
}
|
||||
}
|
||||
|
||||
return Identified
|
||||
})
|
||||
|
||||
const ImplementsIdentifiable = <ID>(defaultID: ID) =>
|
||||
trait(Parent => {
|
||||
abstract class ImplementsIdentifiable extends Identifiable<ID>()(Parent) {
|
||||
id: ID = defaultID
|
||||
}
|
||||
|
||||
return ImplementsIdentifiable
|
||||
})
|
||||
|
||||
|
||||
const Permissible = trait(Parent => {
|
||||
abstract class Permissible extends Parent {
|
||||
static readonly defaultPermissions: string[] = []
|
||||
permissions: string[] = []
|
||||
|
||||
constructor(...args: any[]) {
|
||||
super(...args)
|
||||
console.log("Permissible constructor")
|
||||
}
|
||||
}
|
||||
|
||||
return Permissible
|
||||
})
|
||||
|
||||
|
||||
const UserProto = expresses(
|
||||
// Identifiable<bigint>(),
|
||||
ImplementsIdentifiable(0n),
|
||||
Permissible,
|
||||
)
|
||||
|
||||
class User extends UserProto {
|
||||
constructor(id: bigint) {
|
||||
super()
|
||||
this.id = id
|
||||
}
|
||||
}
|
||||
|
||||
const user1 = new User(1n)
|
||||
console.log(user1)
|
||||
console.log(user1.equals(user1))
|
||||
82
src/tests.ts
82
src/tests.ts
@@ -1,74 +1,62 @@
|
||||
import { AbstractClass } from "type-fest"
|
||||
import { expresses } from "./trait"
|
||||
import { expresses, trait } from "."
|
||||
|
||||
|
||||
function inspectClass(class_: AbstractClass<any, any>) {
|
||||
Object.getOwnPropertyNames(class_).forEach(name => {
|
||||
console.log(
|
||||
"[static]",
|
||||
name,
|
||||
Object.getOwnPropertyDescriptor(class_, name)
|
||||
)
|
||||
})
|
||||
|
||||
Object.getOwnPropertyNames(class_.prototype).forEach(name => {
|
||||
console.log(
|
||||
"[prototype]",
|
||||
name,
|
||||
Object.getOwnPropertyDescriptor(class_.prototype, name)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
abstract class Identified<ID> {
|
||||
const Identifiable = <ID>() =>
|
||||
trait(Parent => {
|
||||
abstract class Identified extends Parent {
|
||||
abstract id: ID
|
||||
|
||||
equals(el: Identified<ID>) {
|
||||
equals(el: Identified) {
|
||||
return this.id === el.id
|
||||
}
|
||||
|
||||
// initializer() {
|
||||
// console.log("Identified initializer")
|
||||
// }
|
||||
}
|
||||
constructor(...args: any[]) {
|
||||
super(...args)
|
||||
console.log("Identified constructor")
|
||||
}
|
||||
}
|
||||
|
||||
class ImplementsIdentifiable<ID> extends Identified<ID> {
|
||||
id!: ID
|
||||
}
|
||||
return Identified
|
||||
})
|
||||
|
||||
const ImplementsIdentifiable = <ID>(defaultID: ID) =>
|
||||
trait(Parent => {
|
||||
abstract class ImplementsIdentifiable extends Identifiable<ID>()(Parent) {
|
||||
id: ID = defaultID
|
||||
}
|
||||
|
||||
return ImplementsIdentifiable
|
||||
})
|
||||
|
||||
|
||||
abstract class Permissible {
|
||||
const Permissible = trait(Parent => {
|
||||
abstract class Permissible extends Parent {
|
||||
static readonly defaultPermissions: string[] = []
|
||||
permissions: string[] = []
|
||||
// permissions!: string[]
|
||||
|
||||
constructor() {
|
||||
constructor(...args: any[]) {
|
||||
super(...args)
|
||||
console.log("Permissible constructor")
|
||||
}
|
||||
|
||||
initializer() {
|
||||
console.log("Permissible initializer")
|
||||
this.permissions = []
|
||||
}
|
||||
}
|
||||
|
||||
return Permissible
|
||||
})
|
||||
|
||||
|
||||
class User extends expresses(
|
||||
Identified as typeof Identified<bigint>,
|
||||
// Identified<string>,
|
||||
const UserProto = expresses(
|
||||
// Identifiable<bigint>(),
|
||||
ImplementsIdentifiable(0n),
|
||||
Permissible,
|
||||
) {
|
||||
readonly id: bigint
|
||||
)
|
||||
|
||||
class User extends UserProto {
|
||||
constructor(id: bigint) {
|
||||
super()
|
||||
this.id = id
|
||||
}
|
||||
}
|
||||
|
||||
const user1 = new User(BigInt(1))
|
||||
const user2 = new User(BigInt(2))
|
||||
|
||||
const user1 = new User(1n)
|
||||
console.log(user1)
|
||||
console.log(user1.equals(user2))
|
||||
console.log(user1.equals(user1))
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
import { AbstractClass, AbstractConstructor, 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>
|
||||
> = Opaque<
|
||||
TraitApplier<C>,
|
||||
"thilatrait/Trait"
|
||||
>
|
||||
|
||||
export type TraitApplier<
|
||||
C extends AbstractClass<any>
|
||||
> =
|
||||
(Parent: AbstractConstructor<any>) => C
|
||||
|
||||
export type UnwrapTraitC<T> =
|
||||
T extends Trait<infer C>
|
||||
? C
|
||||
: never
|
||||
|
||||
|
||||
export function trait<
|
||||
C extends AbstractClass<any>
|
||||
>(
|
||||
applier: TraitApplier<C>
|
||||
) {
|
||||
return applier as Trait<C>
|
||||
}
|
||||
|
||||
|
||||
export function extendsAndExpresses<
|
||||
C extends AbstractClass<any>,
|
||||
Traits extends readonly Trait<any>[],
|
||||
>(
|
||||
extend: C,
|
||||
traits: Traits,
|
||||
) {
|
||||
return traits.reduce(
|
||||
(previous, trait) => trait(previous),
|
||||
extend,
|
||||
) as (
|
||||
AbstractClass<
|
||||
InstanceType<C> &
|
||||
UnionToIntersection<
|
||||
InstanceType<
|
||||
UnwrapTraitC<
|
||||
Traits[number]
|
||||
>
|
||||
>
|
||||
>,
|
||||
|
||||
ConstructorParameters<C>
|
||||
> &
|
||||
|
||||
StaticMembers<C> &
|
||||
StaticMembers<
|
||||
UnionToIntersection<
|
||||
UnwrapTraitC<
|
||||
Traits[number]
|
||||
>
|
||||
>
|
||||
>
|
||||
)
|
||||
}
|
||||
|
||||
export function expresses<
|
||||
Traits extends readonly Trait<any>[],
|
||||
>(
|
||||
...traits: Traits
|
||||
) {
|
||||
return extendsAndExpresses(Object, traits)
|
||||
}
|
||||
Reference in New Issue
Block a user