This commit is contained in:
51
src/Trait.ts
51
src/Trait.ts
@@ -11,41 +11,50 @@ export type TraitApplierSuperTag = "@thilawyn/traitify-ts/TraitApplierSuper"
|
|||||||
export type AddAbstractToImplClass<
|
export type AddAbstractToImplClass<
|
||||||
ImplClass extends Class<{}, []>,
|
ImplClass extends Class<{}, []>,
|
||||||
Abstract extends {},
|
Abstract extends {},
|
||||||
|
StaticAbstract extends {},
|
||||||
> = (
|
> = (
|
||||||
Class<
|
Class<
|
||||||
Abstract & InstanceType<ImplClass>,
|
Abstract & InstanceType<ImplClass>,
|
||||||
ConstructorParameters<ImplClass>
|
ConstructorParameters<ImplClass>
|
||||||
> &
|
> &
|
||||||
|
StaticAbstract &
|
||||||
StaticMembers<ImplClass>
|
StaticMembers<ImplClass>
|
||||||
)
|
)
|
||||||
|
|
||||||
export type RemoveAbstractFromImplClass<
|
export type RemoveAbstractFromImplClass<
|
||||||
ImplClassWithAbstract extends Class<Abstract, []> & { _tag: TraitApplierSuperTag },
|
ImplClassWithAbstract extends Class<Abstract, []> & { _tag: TraitApplierSuperTag },
|
||||||
Abstract extends {},
|
Abstract extends {},
|
||||||
|
StaticAbstract extends {},
|
||||||
> = (
|
> = (
|
||||||
Class<
|
Class<
|
||||||
Omit<InstanceType<ImplClassWithAbstract>, keyof Abstract>,
|
Omit<InstanceType<ImplClassWithAbstract>, keyof Abstract>,
|
||||||
ConstructorParameters<ImplClassWithAbstract>
|
ConstructorParameters<ImplClassWithAbstract>
|
||||||
> &
|
> &
|
||||||
Omit<StaticMembers<ImplClassWithAbstract>, "_tag">
|
Omit<StaticMembers<ImplClassWithAbstract>, keyof StaticAbstract | "_tag">
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
export class Trait<
|
export class Trait<
|
||||||
Supertraits extends TraitExpression<typeof TraitExpression.NullSuperclass, Trait<any, any, any>[], Trait<any, any, any>[]>,
|
Supertraits extends TraitExpression<
|
||||||
|
typeof TraitExpression.NullSuperclass,
|
||||||
|
Trait<any, any, any, any>[],
|
||||||
|
Trait<any, any, any, any>[]
|
||||||
|
>,
|
||||||
Abstract extends {},
|
Abstract extends {},
|
||||||
|
StaticAbstract extends {},
|
||||||
ImplClass extends Class<{}, []>,
|
ImplClass extends Class<{}, []>,
|
||||||
> {
|
> {
|
||||||
constructor(
|
constructor(
|
||||||
readonly supertraits: Supertraits,
|
readonly supertraits: Supertraits,
|
||||||
readonly abstract: Abstract,
|
readonly abstract: Abstract,
|
||||||
|
readonly staticAbstract: StaticAbstract,
|
||||||
readonly apply: (Super: AbstractClass<{}>) => ImplClass,
|
readonly apply: (Super: AbstractClass<{}>) => ImplClass,
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace Trait {
|
export namespace Trait {
|
||||||
export type OwnSupertraits<T> = (
|
export type OwnSupertraits<T> = (
|
||||||
T extends Trait<infer Supertraits, any, any>
|
T extends Trait<infer Supertraits, any, any, any>
|
||||||
? Supertraits
|
? Supertraits
|
||||||
: never
|
: never
|
||||||
)
|
)
|
||||||
@@ -54,7 +63,7 @@ export namespace Trait {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type OwnAbstract<T> = (
|
export type OwnAbstract<T> = (
|
||||||
T extends Trait<any, infer Abstract, any>
|
T extends Trait<any, infer Abstract, any, any>
|
||||||
? Abstract
|
? Abstract
|
||||||
: never
|
: never
|
||||||
)
|
)
|
||||||
@@ -62,8 +71,17 @@ export namespace Trait {
|
|||||||
return: Trait.OwnAbstract<this["arg0"]>
|
return: Trait.OwnAbstract<this["arg0"]>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type OwnStaticAbstract<T> = (
|
||||||
|
T extends Trait<any, any, infer StaticAbstract, any>
|
||||||
|
? StaticAbstract
|
||||||
|
: never
|
||||||
|
)
|
||||||
|
export interface OwnStaticAbstractFn extends Fn {
|
||||||
|
return: Trait.OwnAbstract<this["arg0"]>
|
||||||
|
}
|
||||||
|
|
||||||
export type OwnImplClass<T> = (
|
export type OwnImplClass<T> = (
|
||||||
T extends Trait<any, any, infer ImplClass>
|
T extends Trait<any, any, any, infer ImplClass>
|
||||||
? ImplClass
|
? ImplClass
|
||||||
: never
|
: never
|
||||||
)
|
)
|
||||||
@@ -72,38 +90,28 @@ export namespace Trait {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type OwnImplInstance<T> = (
|
export type OwnImplInstance<T> = (
|
||||||
T extends Trait<any, any, infer ImplClass>
|
InstanceType<Trait.OwnImplClass<T>>
|
||||||
? InstanceType<ImplClass>
|
|
||||||
: never
|
|
||||||
)
|
)
|
||||||
export interface OwnImplInstanceFn extends Fn {
|
export interface OwnImplInstanceFn extends Fn {
|
||||||
return: Trait.OwnImplInstance<this["arg0"]>
|
return: Trait.OwnImplInstance<this["arg0"]>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OwnClass<T> = (
|
export type OwnClass<T> = (
|
||||||
T extends Trait<any, infer Abstract, infer ImplClass>
|
AddAbstractToImplClass<Trait.OwnImplClass<T>, Trait.OwnAbstract<T>, Trait.OwnStaticAbstract<T>>
|
||||||
? AddAbstractToImplClass<ImplClass, Abstract>
|
|
||||||
: never
|
|
||||||
)
|
)
|
||||||
export interface OwnClassFn extends Fn {
|
export interface OwnClassFn extends Fn {
|
||||||
return: Trait.OwnClass<this["arg0"]>
|
return: Trait.OwnClass<this["arg0"]>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OwnInstance<T> = (
|
export type OwnInstance<T> = (
|
||||||
T extends Trait<any, infer Abstract, infer ImplClass>
|
InstanceType<Trait.OwnClass<T>>
|
||||||
? InstanceType<
|
|
||||||
AddAbstractToImplClass<ImplClass, Abstract>
|
|
||||||
>
|
|
||||||
: never
|
|
||||||
)
|
)
|
||||||
export interface OwnInstanceFn extends Fn {
|
export interface OwnInstanceFn extends Fn {
|
||||||
return: Trait.OwnInstance<this["arg0"]>
|
return: Trait.OwnInstance<this["arg0"]>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Supertraits<T> = (
|
export type Supertraits<T> = (
|
||||||
T extends Trait<infer Supertraits, any, any>
|
TraitExpression.AllTraits<Trait.OwnSupertraits<T>>
|
||||||
? TraitExpression.AllTraits<Supertraits>
|
|
||||||
: never
|
|
||||||
)
|
)
|
||||||
export interface SupertraitsFn extends Fn {
|
export interface SupertraitsFn extends Fn {
|
||||||
return: Trait.Supertraits<this["arg0"]>
|
return: Trait.Supertraits<this["arg0"]>
|
||||||
@@ -144,14 +152,17 @@ export namespace Trait {
|
|||||||
|
|
||||||
export function trait<
|
export function trait<
|
||||||
Abstract extends {},
|
Abstract extends {},
|
||||||
|
StaticAbstract extends {},
|
||||||
ImplClassWithAbstract extends Class<Abstract, []> & { _tag: TraitApplierSuperTag },
|
ImplClassWithAbstract extends Class<Abstract, []> & { _tag: TraitApplierSuperTag },
|
||||||
>(
|
>(
|
||||||
abstract: Opaque<Abstract, AbstractTag>,
|
abstract: Opaque<Abstract, AbstractTag>,
|
||||||
|
staticAbstract: Opaque<StaticAbstract, AbstractTag>,
|
||||||
apply: (Super: AbstractClass<Abstract> & { _tag: TraitApplierSuperTag }) => ImplClassWithAbstract,
|
apply: (Super: AbstractClass<Abstract> & { _tag: TraitApplierSuperTag }) => ImplClassWithAbstract,
|
||||||
) {
|
) {
|
||||||
return new Trait(
|
return new Trait(
|
||||||
emptyTraitExpression,
|
emptyTraitExpression,
|
||||||
abstract as Abstract,
|
abstract as Abstract,
|
||||||
apply as any as (Super: AbstractClass<{}>) => RemoveAbstractFromImplClass<ImplClassWithAbstract, Abstract>,
|
staticAbstract as StaticAbstract,
|
||||||
|
apply as any as (Super: AbstractClass<{}>) => RemoveAbstractFromImplClass<ImplClassWithAbstract, Abstract, StaticAbstract>,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import { ExtendFn, SimplifyFn, StaticMembersFn } from "./util"
|
|||||||
|
|
||||||
export class TraitExpression<
|
export class TraitExpression<
|
||||||
Superclass extends AbstractClass<{}>,
|
Superclass extends AbstractClass<{}>,
|
||||||
const OwnTraits extends Trait<any, any, any>[],
|
const OwnTraits extends Trait<any, any, any, any>[],
|
||||||
const AllTraits extends Trait<any, any, any>[],
|
const AllTraits extends Trait<any, any, any, any>[],
|
||||||
> {
|
> {
|
||||||
constructor(
|
constructor(
|
||||||
readonly superclass: Superclass,
|
readonly superclass: Superclass,
|
||||||
@@ -52,17 +52,20 @@ export class TraitExpression<
|
|||||||
subtrait<
|
subtrait<
|
||||||
This extends TraitExpression<typeof TraitExpression.NullSuperclass, any, any>,
|
This extends TraitExpression<typeof TraitExpression.NullSuperclass, any, any>,
|
||||||
SubtraitAbstract extends Implements<This>,
|
SubtraitAbstract extends Implements<This>,
|
||||||
|
SubtraitStaticAbstract extends StaticImplements<This>,
|
||||||
SubtraitImplClassWithAbstract extends Class<SubtraitAbstract, []> & { _tag: TraitApplierSuperTag },
|
SubtraitImplClassWithAbstract extends Class<SubtraitAbstract, []> & { _tag: TraitApplierSuperTag },
|
||||||
>(
|
>(
|
||||||
this: This,
|
this: This,
|
||||||
abstract: (expression: This) => Opaque<SubtraitAbstract, AbstractTag>,
|
abstract: (expression: This) => Opaque<SubtraitAbstract, AbstractTag>,
|
||||||
|
staticAbstract: (expression: This) => Opaque<SubtraitStaticAbstract, AbstractTag>,
|
||||||
apply: (Super: AbstractClass<SubtraitAbstract> & { _tag: TraitApplierSuperTag }) => SubtraitImplClassWithAbstract,
|
apply: (Super: AbstractClass<SubtraitAbstract> & { _tag: TraitApplierSuperTag }) => SubtraitImplClassWithAbstract,
|
||||||
) {
|
) {
|
||||||
return new Trait(
|
return new Trait(
|
||||||
this,
|
this,
|
||||||
// {} as RemoveSupertraitsAbstractFromAbstract<SubtraitAbstract, Implements<typeof this>>,
|
// {} as RemoveSupertraitsAbstractFromAbstract<SubtraitAbstract, Implements<typeof this>>,
|
||||||
{} as SubtraitAbstract, // TODO: find a way to cleanly substract Implements<typeof this> from this.
|
{} as SubtraitAbstract, // TODO: find a way to cleanly substract Implements<typeof this> from this.
|
||||||
apply as any as (Super: AbstractClass<{}>) => RemoveAbstractFromImplClass<SubtraitImplClassWithAbstract, SubtraitAbstract>,
|
{} as SubtraitStaticAbstract,
|
||||||
|
apply as any as (Super: AbstractClass<{}>) => RemoveAbstractFromImplClass<SubtraitImplClassWithAbstract, SubtraitAbstract, SubtraitStaticAbstract>,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,3 +114,12 @@ export type Implements<Exp extends TraitExpression<any, any, any>> = (
|
|||||||
SimplifyFn,
|
SimplifyFn,
|
||||||
]>
|
]>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export type StaticImplements<Exp extends TraitExpression<any, any, any>> = (
|
||||||
|
Pipe<Exp, [
|
||||||
|
TraitExpression.AllTraitsFn,
|
||||||
|
Tuples.Map<Trait.OwnStaticAbstractFn>,
|
||||||
|
ExtendFn,
|
||||||
|
SimplifyFn,
|
||||||
|
]>
|
||||||
|
)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { TraitExpression, emptyTraitExpression } from "./TraitExpression"
|
|||||||
import { ExtendableFn, StaticMembersFn } from "./util"
|
import { ExtendableFn, StaticMembersFn } from "./util"
|
||||||
|
|
||||||
|
|
||||||
type SpreadSupertraits<Traits extends Trait<any, any, any>[]> = (
|
type SpreadSupertraits<Traits extends Trait<any, any, any, any>[]> = (
|
||||||
Call<
|
Call<
|
||||||
Tuples.FlatMap<PrependTraitSupertraitsFn>,
|
Tuples.FlatMap<PrependTraitSupertraitsFn>,
|
||||||
Traits
|
Traits
|
||||||
@@ -18,7 +18,7 @@ interface PrependTraitSupertraitsFn extends Fn {
|
|||||||
|
|
||||||
type AbstractMembersExtendable<
|
type AbstractMembersExtendable<
|
||||||
Superclass extends AbstractClass<{}>,
|
Superclass extends AbstractClass<{}>,
|
||||||
Traits extends Trait<any, any, any>[],
|
Traits extends Trait<any, any, any, any>[],
|
||||||
> = (
|
> = (
|
||||||
Pipe<Traits, [
|
Pipe<Traits, [
|
||||||
Tuples.Map<Trait.OwnAbstractFn>,
|
Tuples.Map<Trait.OwnAbstractFn>,
|
||||||
@@ -28,7 +28,7 @@ type AbstractMembersExtendable<
|
|||||||
|
|
||||||
type ImplInstanceExtendable<
|
type ImplInstanceExtendable<
|
||||||
Superclass extends AbstractClass<{}>,
|
Superclass extends AbstractClass<{}>,
|
||||||
Traits extends Trait<any, any, any>[],
|
Traits extends Trait<any, any, any, any>[],
|
||||||
> = (
|
> = (
|
||||||
Pipe<Traits, [
|
Pipe<Traits, [
|
||||||
Tuples.Map<Trait.OwnImplInstanceFn>,
|
Tuples.Map<Trait.OwnImplInstanceFn>,
|
||||||
@@ -38,7 +38,7 @@ type ImplInstanceExtendable<
|
|||||||
|
|
||||||
type ImplStaticMembersExtendable<
|
type ImplStaticMembersExtendable<
|
||||||
Superclass extends AbstractClass<{}>,
|
Superclass extends AbstractClass<{}>,
|
||||||
Traits extends Trait<any, any, any>[],
|
Traits extends Trait<any, any, any, any>[],
|
||||||
> = (
|
> = (
|
||||||
Pipe<Traits, [
|
Pipe<Traits, [
|
||||||
Tuples.Map<Trait.OwnImplClassFn>,
|
Tuples.Map<Trait.OwnImplClassFn>,
|
||||||
@@ -50,8 +50,8 @@ type ImplStaticMembersExtendable<
|
|||||||
|
|
||||||
type BuildTraitExpression<
|
type BuildTraitExpression<
|
||||||
Superclass extends AbstractClass<{}>,
|
Superclass extends AbstractClass<{}>,
|
||||||
OwnTraits extends Trait<any, any, any>[],
|
OwnTraits extends Trait<any, any, any, any>[],
|
||||||
AllTraits extends Trait<any, any, any>[],
|
AllTraits extends Trait<any, any, any, any>[],
|
||||||
> = (
|
> = (
|
||||||
AbstractMembersExtendable<Superclass, AllTraits> extends false
|
AbstractMembersExtendable<Superclass, AllTraits> extends false
|
||||||
? "Type conflict between the traits abstract members and/or the superclass instance."
|
? "Type conflict between the traits abstract members and/or the superclass instance."
|
||||||
@@ -65,8 +65,8 @@ type BuildTraitExpression<
|
|||||||
|
|
||||||
class TraitExpressionBuilder<
|
class TraitExpressionBuilder<
|
||||||
Superclass extends AbstractClass<{}>,
|
Superclass extends AbstractClass<{}>,
|
||||||
const OwnTraits extends Trait<any, any, any>[],
|
const OwnTraits extends Trait<any, any, any, any>[],
|
||||||
const AllTraits extends Trait<any, any, any>[],
|
const AllTraits extends Trait<any, any, any, any>[],
|
||||||
> {
|
> {
|
||||||
constructor(private expression: TraitExpression<Superclass, OwnTraits, AllTraits>) {}
|
constructor(private expression: TraitExpression<Superclass, OwnTraits, AllTraits>) {}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ class TraitExpressionBuilder<
|
|||||||
}
|
}
|
||||||
|
|
||||||
expresses<
|
expresses<
|
||||||
const Traits extends Trait<any, any, any>[]
|
const Traits extends Trait<any, any, any, any>[]
|
||||||
>(
|
>(
|
||||||
...traits: Traits
|
...traits: Traits
|
||||||
): TraitExpressionBuilder<
|
): TraitExpressionBuilder<
|
||||||
@@ -104,7 +104,8 @@ class TraitExpressionBuilder<
|
|||||||
|
|
||||||
private spreadSupertraits<
|
private spreadSupertraits<
|
||||||
const Traits extends Trait<
|
const Traits extends Trait<
|
||||||
TraitExpression<any, any, Trait<any, any, any>[]>,
|
TraitExpression<any, any, Trait<any, any, any, any>[]>,
|
||||||
|
any,
|
||||||
any,
|
any,
|
||||||
any
|
any
|
||||||
>[]
|
>[]
|
||||||
|
|||||||
13
src/tests.ts
13
src/tests.ts
@@ -1,10 +1,11 @@
|
|||||||
import { Trait, trait } from "./Trait"
|
import { Trait, trait } from "./Trait"
|
||||||
import { Implements } from "./TraitExpression"
|
import { Implements, StaticImplements } from "./TraitExpression"
|
||||||
import { expression } from "./TraitExpressionBuilder"
|
import { expression } from "./TraitExpressionBuilder"
|
||||||
import { abstract } from "./abstract"
|
import { abstract } from "./abstract"
|
||||||
|
|
||||||
|
|
||||||
const PrintsHelloOnNew = trait(
|
const PrintsHelloOnNew = trait(
|
||||||
|
abstract(),
|
||||||
abstract(),
|
abstract(),
|
||||||
Super => class PrintsHelloOnNew extends Super {
|
Super => class PrintsHelloOnNew extends Super {
|
||||||
static readonly isPrintsHelloOnNew = true
|
static readonly isPrintsHelloOnNew = true
|
||||||
@@ -19,6 +20,7 @@ type PrintsHelloOnNewClass = Trait.Class<typeof PrintsHelloOnNew>
|
|||||||
|
|
||||||
const Identifiable = <ID>() => trait(
|
const Identifiable = <ID>() => trait(
|
||||||
abstract<{ readonly id: ID }>(),
|
abstract<{ readonly id: ID }>(),
|
||||||
|
abstract(),
|
||||||
Super => class Identifiable extends Super {
|
Super => class Identifiable extends Super {
|
||||||
equals(el: Identifiable) {
|
equals(el: Identifiable) {
|
||||||
return this.id === el.id
|
return this.id === el.id
|
||||||
@@ -35,6 +37,7 @@ const StatefulSubscription = trait(
|
|||||||
{ _tag: "expired", expiredSince: Date }
|
{ _tag: "expired", expiredSince: Date }
|
||||||
)
|
)
|
||||||
}>(),
|
}>(),
|
||||||
|
abstract(),
|
||||||
|
|
||||||
Super => class StatefulSubscription extends Super {},
|
Super => class StatefulSubscription extends Super {},
|
||||||
)
|
)
|
||||||
@@ -53,6 +56,8 @@ const ActiveStatefulSubscription = expression
|
|||||||
return abstract<IActiveStatefulSubscription>()
|
return abstract<IActiveStatefulSubscription>()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
exp => abstract<StaticImplements<typeof exp>>(),
|
||||||
|
|
||||||
Super => class ActiveStatefulSubscription extends Super {},
|
Super => class ActiveStatefulSubscription extends Super {},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -86,7 +91,9 @@ class User extends exp.extends implements Implements<typeof exp> {
|
|||||||
console.log(new User())
|
console.log(new User())
|
||||||
|
|
||||||
|
|
||||||
declare function StaticImplements(target: { issou: string }, context: any): typeof target
|
declare function StaticImplements(target: { issou: string }, context: any): void
|
||||||
|
|
||||||
@StaticImplements
|
@StaticImplements
|
||||||
class Gneugneu {}
|
class Gneugneu {
|
||||||
|
// static issou: string = "juif"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user