diff --git a/bun.lockb b/bun.lockb index 1aa0c80..0e06437 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 1b4681c..0f8bae7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@thilawyn/traitify-ts", - "version": "0.1.3", + "version": "0.1.4", "type": "module", "publishConfig": { "registry": "https://git.jvalver.de/api/packages/thilawyn/npm/" @@ -28,18 +28,19 @@ "clean:node": "rm -rf node_modules" }, "dependencies": { - "hotscript": "^1.0.13", + "lodash-es": "^4.17.21", "type-fest": "^4.10.2" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.3", + "@types/lodash-es": "^4.17.12", "bun-types": "latest", - "npm-check-updates": "^16.14.14", + "npm-check-updates": "^16.14.15", "npm-sort": "^0.0.4", - "rollup": "^4.9.6", + "rollup": "^4.12.0", "rollup-plugin-cleanup": "^3.2.1", "rollup-plugin-ts": "^3.4.5", - "tsx": "^4.7.0", + "tsx": "^4.7.1", "typescript": "^5.3.3" } } diff --git a/src/Trait.ts b/src/Trait.ts index 84516b2..9d43662 100644 --- a/src/Trait.ts +++ b/src/Trait.ts @@ -1,157 +1,136 @@ -import { Fn, Pipe, Tuples } from "hotscript" -import { AbstractClass, Class, Opaque } from "type-fest" -import { TraitExpression, emptyTraitExpression } from "./TraitExpression" -import { AbstractTag } from "./abstract" -import { ExtendFn, SimplifyFn, StaticMembers, StaticMembersFn } from "./util" - - -export type TraitApplierSuperTag = "@thilawyn/traitify-ts/TraitApplierSuper" - - -export type AddAbstractToImplClass< - ImplClass extends Class<{}, []>, - Abstract extends {}, -> = ( - Class< - Abstract & InstanceType, - ConstructorParameters - > & - StaticMembers -) - -export type RemoveAbstractFromImplClass< - ImplClassWithAbstract extends Class & { _tag: TraitApplierSuperTag }, - Abstract extends {}, -> = ( - Class< - Omit, keyof Abstract>, - ConstructorParameters - > & - Omit, "_tag"> -) +import { AbstractClass, Class, Simplify } from "type-fest" +import { TraitExpression } from "./TraitExpression" +import { Extend, StaticMembers } from "./util" export class Trait< - Supertraits extends TraitExpression[], Trait[]>, - Abstract extends {}, - ImplClass extends Class<{}, []>, + SuperExpression extends TraitExpression< + typeof TraitExpression.NullSuperclass, + Trait[] + >, + Abstract extends object, + StaticAbstract extends object, + ImplClass extends AbstractClass, > { constructor( - readonly supertraits: Supertraits, - readonly abstract: Abstract, - readonly apply: (Super: AbstractClass<{}>) => ImplClass, + readonly superExpression: SuperExpression, + readonly abstract: Abstract, + readonly staticAbstract: StaticAbstract, + readonly apply: (Super: AbstractClass) => ImplClass, ) {} } export namespace Trait { - export type OwnSupertraits = ( - T extends Trait - ? Supertraits + export type SuperExpression = ( + T extends Trait + ? SuperExpression : never ) - export interface OwnSupertraitsFn extends Fn { - return: Trait.OwnSupertraits - } - export type OwnAbstract = ( - T extends Trait + export type Supertraits = ( + TraitExpression.Traits> + ) + + export type Abstract = ( + T extends Trait ? Abstract : never ) - export interface OwnAbstractFn extends Fn { - return: Trait.OwnAbstract - } - export type OwnImplClass = ( - T extends Trait + export type StaticAbstract = ( + T extends Trait + ? StaticAbstract + : never + ) + + export type ImplClass = ( + T extends Trait ? ImplClass : never ) - export interface OwnImplClassFn extends Fn { - return: Trait.OwnImplClass - } - export type OwnImplInstance = ( - T extends Trait - ? InstanceType - : never + export type ImplInstance = ( + InstanceType> ) - export interface OwnImplInstanceFn extends Fn { - return: Trait.OwnImplInstance - } - export type OwnClass = ( - T extends Trait - ? AddAbstractToImplClass - : never + export type ImplStaticMembers = ( + StaticMembers> ) - export interface OwnClassFn extends Fn { - return: Trait.OwnClass - } - - export type OwnInstance = ( - T extends Trait - ? InstanceType< - AddAbstractToImplClass - > - : never - ) - export interface OwnInstanceFn extends Fn { - return: Trait.OwnInstance - } - - export type Supertraits = ( - T extends Trait - ? TraitExpression.AllTraits - : never - ) - export interface SupertraitsFn extends Fn { - return: Trait.Supertraits - } - - export type Class = ( - AbstractClass< - Trait.Instance, - any[] - > & - Pipe, - Tuples.Map, - Tuples.Map, - ExtendFn, - SimplifyFn, - ]> - ) - export interface ClassFn extends Fn { - return: Trait.Class - } export type Instance = ( - Pipe, - Tuples.Map, - ExtendFn, - SimplifyFn, + Extend<[ + Trait.Abstract, + Trait.ImplInstance, ]> ) - export interface InstanceFn extends Fn { - return: Trait.Instance + + export type Static = ( + Extend<[ + Trait.StaticAbstract, + Trait.ImplStaticMembers, + ]> + ) +} + +export namespace TraitTuple { + export type MapAbstract = { + [K in keyof T]: K extends keyof [] + ? T[K] + : Trait.Abstract + } + + export type MapStaticAbstract = { + [K in keyof T]: K extends keyof [] + ? T[K] + : Trait.StaticAbstract + } + + export type MapImplClass = { + [K in keyof T]: K extends keyof [] + ? T[K] + : Trait.ImplClass + } + + export type MapImplInstance = { + [K in keyof T]: K extends keyof [] + ? T[K] + : Trait.ImplInstance + } + + export type MapImplStaticMembers = { + [K in keyof T]: K extends keyof [] + ? T[K] + : Trait.ImplStaticMembers + } + + export type MapInstance = { + [K in keyof T]: K extends keyof [] + ? T[K] + : Trait.Instance + } + + export type MapStaticMembers = { + [K in keyof T]: K extends keyof [] + ? T[K] + : Trait.Static } } -export function trait< - Abstract extends {}, - ImplClassWithAbstract extends Class & { _tag: TraitApplierSuperTag }, ->( - abstract: Opaque, - apply: (Super: AbstractClass & { _tag: TraitApplierSuperTag }) => ImplClassWithAbstract, -) { - return new Trait( - emptyTraitExpression, - abstract as Abstract, - apply as any as (Super: AbstractClass<{}>) => RemoveAbstractFromImplClass, - ) -} +export type TraitClass> = ( + AbstractClass, any[]> & + TraitStaticMembers +) + +export type TraitConcreteClass> = ( + Class, any[]> & + TraitStaticMembers +) + +export type TraitInstance> = ( + Simplify> +) + +export type TraitStaticMembers> = ( + Simplify> +) diff --git a/src/TraitBuilder.ts b/src/TraitBuilder.ts new file mode 100644 index 0000000..a59b333 --- /dev/null +++ b/src/TraitBuilder.ts @@ -0,0 +1,121 @@ +import { AbstractClass, Simplify } from "type-fest" +import { Trait } from "./Trait" +import { TraitExpression } from "./TraitExpression" +import { Extend, StaticMembers } from "./util" + + +declare const implSuperSymbol: unique symbol + +type ImplSuper = ( + This extends TraitBuilder< + any, + infer Abstract, + infer StaticAbstract, + infer ImplClass + > + ? ( + AbstractClass< + Simplify< + Extend<[ + Abstract, + InstanceType, + ]> + > + > & + + Simplify< + Extend<[ + StaticAbstract, + StaticMembers, + ]> + > & + { readonly [implSuperSymbol]: true } + ) + : never +) + + +export class TraitBuilder< + SuperExpression extends TraitExpression< + typeof TraitExpression.NullSuperclass, + Trait[] + >, + Abstract extends object, + StaticAbstract extends object, + ImplClass extends AbstractClass, +> { + constructor( + private readonly traitSuperExpression: SuperExpression, + private readonly traitAbstract: Abstract, + private readonly traitStaticAbstract: StaticAbstract, + private readonly traitApply: (Super: AbstractClass) => ImplClass, + ) {} + + abstract( + _: (Super: AbstractClass) => AbstractClass + ) { + return new TraitBuilder( + this.traitSuperExpression, + {} as Simplify, + this.traitStaticAbstract, + this.traitApply, + ) + } + + staticAbstract( + _: (Super: AbstractClass) => AbstractClass + ) { + return new TraitBuilder( + this.traitSuperExpression, + this.traitAbstract, + {} as Simplify, + this.traitApply, + ) + } + + implement< + ImplClassWithAbstract extends ImplSuper // TODO: find a way to set the constraint to concrete classes while keeping the Super arg as an abstract class + >( + apply: (Super: ImplSuper) => ImplClassWithAbstract + ) { + return new TraitBuilder( + this.traitSuperExpression, + this.traitAbstract, + this.traitStaticAbstract, + + apply as unknown as (Super: AbstractClass) => ( + AbstractClass< + Simplify< + Omit< + InstanceType, + keyof Abstract + > + > + > & + + Simplify< + Omit< + StaticMembers, + keyof StaticAbstract | typeof implSuperSymbol + > + > + ), + ) + } + + build() { + return new Trait( + this.traitSuperExpression, + this.traitAbstract, + this.traitStaticAbstract, + this.traitApply, + ) + } +} + +export const trait = new TraitBuilder( + new TraitExpression(TraitExpression.NullSuperclass, []), + {} as object, + {} as object, + Super => class extends Super {} as AbstractClass, +) diff --git a/src/TraitExpression.ts b/src/TraitExpression.ts index d5bfed3..2490377 100644 --- a/src/TraitExpression.ts +++ b/src/TraitExpression.ts @@ -1,113 +1,163 @@ -import { Fn, Pipe, Tuples } from "hotscript" -import { AbstractClass, Class, Opaque } from "type-fest" -import { RemoveAbstractFromImplClass, Trait, TraitApplierSuperTag } from "./Trait" -import { AbstractTag } from "./abstract" -import { ExtendFn, SimplifyFn, StaticMembersFn } from "./util" - - -// type RemoveSupertraitsAbstractFromAbstract = { -// [Key in Extract]: Left[Key] -// } & { -// [Key in Exclude]: Left[Key] -// } +import { AbstractClass, Class, Simplify } from "type-fest" +import { Trait, TraitTuple } from "./Trait" +import { TraitBuilder } from "./TraitBuilder" +import { Extend, StaticMembers } from "./util" export class TraitExpression< - Superclass extends AbstractClass<{}>, - const OwnTraits extends Trait[], - const AllTraits extends Trait[], + Superclass extends AbstractClass, + const Traits extends Trait[], > { constructor( readonly superclass: Superclass, - readonly ownTraits: OwnTraits, - readonly allTraits: AllTraits, + readonly traits: Traits, ) {} get extends(): ( AbstractClass< - Pipe, // Map all the traits to the instance of their implementation class - Tuples.Prepend>, // Add the instance of the superclass at the top of the list - ExtendFn, // Reduce to a single instance that extends all the instances in the list - SimplifyFn, // Make readable for IDEs - ]>, + InstanceType & // Keep the instance of the superclass outside of any kind of type manipulation + // as it can accidentely remove abstract properties + Simplify< + Extend< + TraitTuple.MapImplInstance + > + >, ConstructorParameters > & - Pipe, // Map all the traits to their implementation class - Tuples.Prepend, // Add the superclass at the top of the list - Tuples.Map, // Map all the classes to an object containing their static members - ExtendFn, // Reduce to a single object that extends all the objects in the list - SimplifyFn, // Make readable for IDEs - ]> + Simplify< + Extend<[ + StaticMembers, + ...TraitTuple.MapImplStaticMembers, + ]> + > ) { - return this.allTraits.reduce( + return this.traits.reduce( (previous, trait) => trait.apply(previous), this.superclass, ) as any } + implementsStatic(target: ImplementsStatic, context: any) {} + subtrait< - This extends TraitExpression, - SubtraitAbstract extends Implements, - SubtraitImplClassWithAbstract extends Class & { _tag: TraitApplierSuperTag }, + This extends TraitExpression >( - this: This, - abstract: (expression: This) => Opaque, - apply: (Super: AbstractClass & { _tag: TraitApplierSuperTag }) => SubtraitImplClassWithAbstract, + this: This ) { - return new Trait( + return new TraitBuilder< + This, + + Simplify< + Extend> + >, + Simplify< + Extend> + >, + + AbstractClass< + Simplify< + Extend> + > + > & + Simplify< + Extend> + > + >( this, - // {} as RemoveSupertraitsAbstractFromAbstract>, - {} as SubtraitAbstract, // TODO: find a way to cleanly substract Implements from this. - apply as any as (Super: AbstractClass<{}>) => RemoveAbstractFromImplClass, + {} as any, + {} as any, + Super => class extends Super {} as any, ) } } export namespace TraitExpression { + declare const nullSuperclassSymbol: unique symbol export class NullSuperclass { - static readonly _tag = "@thilawyn/traitify-ts/TraitExpression.NullSuperclass" + static readonly [nullSuperclassSymbol]: true + constructor(...args: any[]) {} } export type Superclass = ( - T extends TraitExpression + T extends TraitExpression ? Superclass : never ) - export interface SuperclassFn extends Fn { - return: TraitExpression.Superclass - } - export type OwnTraits = ( - T extends TraitExpression - ? OwnTraits + export type Traits = ( + T extends TraitExpression + ? Traits : never ) - export interface OwnTraitsFn extends Fn { - return: TraitExpression.OwnTraits - } - - export type AllTraits = ( - T extends TraitExpression - ? AllTraits - : never - ) - export interface AllTraitsFn extends Fn { - return: TraitExpression.AllTraits - } } -export const emptyTraitExpression = new TraitExpression(TraitExpression.NullSuperclass, [], []) - -export type Implements> = ( - Pipe, - ExtendFn, - SimplifyFn, - ]> +export type Implements< + Exp extends TraitExpression[]> +> = ( + Simplify< + Extend< + TraitTuple.MapAbstract< + TraitExpression.Traits + > + > + > +) + +export type ImplementsStatic< + Exp extends TraitExpression[]> +> = ( + Simplify< + Extend< + TraitTuple.MapStaticAbstract< + TraitExpression.Traits + > + > + > +) + + +export type TraitExpressionClass< + Exp extends TraitExpression[]> +> = ( + AbstractClass< + TraitExpressionInstance, + ConstructorParameters> + > & + TraitExpressionStaticMembers +) + +export type TraitExpressionConcreteClass< + Exp extends TraitExpression[]> +> = ( + Class< + TraitExpressionInstance, + ConstructorParameters> + > & + TraitExpressionStaticMembers +) + +export type TraitExpressionInstance< + Exp extends TraitExpression[]> +> = ( + InstanceType> & // Keep the instance of the superclass outside of any kind of type manipulation + // as it can accidentely remove abstract properties + Simplify< + Extend< + TraitTuple.MapInstance> + > + > +) + +export type TraitExpressionStaticMembers< + Exp extends TraitExpression[]> +> = ( + Simplify< + Extend<[ + StaticMembers>, + ...TraitTuple.MapStaticMembers>, + ]> + > ) diff --git a/src/TraitExpressionBuilder.ts b/src/TraitExpressionBuilder.ts index c1f5064..d1fdeec 100644 --- a/src/TraitExpressionBuilder.ts +++ b/src/TraitExpressionBuilder.ts @@ -1,129 +1,120 @@ -import { Call, Fn, Pipe, Tuples } from "hotscript" +import { uniq } from "lodash-es" import { AbstractClass } from "type-fest" -import { Trait } from "./Trait" -import { TraitExpression, emptyTraitExpression } from "./TraitExpression" -import { ExtendableFn, StaticMembersFn } from "./util" +import { Trait, TraitTuple } from "./Trait" +import { TraitExpression } from "./TraitExpression" +import { Extendable, StaticMembers } from "./util" -type SpreadSupertraits[]> = ( - Call< - Tuples.FlatMap, - Traits - > +type SpreadSupertraits = ( + T extends [infer Trait, ...infer Rest] + ? [ + ...Trait.Supertraits, + Trait, + ...SpreadSupertraits, + ] + : [] ) -interface PrependTraitSupertraitsFn extends Fn { - return: [...Trait.Supertraits, this["arg0"]] -} -type AbstractMembersExtendable< - Superclass extends AbstractClass<{}>, - Traits extends Trait[], +type InstanceExtendable< + Superclass extends AbstractClass, + Traits extends Trait[], > = ( - Pipe, - Tuples.Prepend>, + Extendable<[ + InstanceType, + ...TraitTuple.MapInstance, ]> ) -type ImplInstanceExtendable< - Superclass extends AbstractClass<{}>, - Traits extends Trait[], +type StaticMembersExtendable< + Superclass extends AbstractClass, + Traits extends Trait[], > = ( - Pipe, - Tuples.Prepend>, - ]> -) - -type ImplStaticMembersExtendable< - Superclass extends AbstractClass<{}>, - Traits extends Trait[], -> = ( - Pipe, - Tuples.Prepend, - Tuples.Map, - ExtendableFn, + Extendable<[ + StaticMembers, + ...TraitTuple.MapStaticMembers, ]> ) type BuildTraitExpression< - Superclass extends AbstractClass<{}>, - OwnTraits extends Trait[], - AllTraits extends Trait[], + Superclass extends AbstractClass, + Traits extends Trait[], > = ( - AbstractMembersExtendable extends false - ? "Type conflict between the traits abstract members and/or the superclass instance." - : ImplInstanceExtendable extends false - ? "Type conflict between the traits implementation instances and/or the superclass instance." - : ImplStaticMembersExtendable extends false - ? "Type conflict between the traits implementation static members and/or the superclass static members." - : TraitExpression + InstanceExtendable extends false + ? "Type conflict on the instance side." + : StaticMembersExtendable extends false + ? "Type conflict on the static side." + : TraitExpression ) class TraitExpressionBuilder< - Superclass extends AbstractClass<{}>, - const OwnTraits extends Trait[], - const AllTraits extends Trait[], + Superclass extends AbstractClass, + const Traits extends Trait[], > { - constructor(private expression: TraitExpression) {} + constructor( + private readonly expressionSuperclass: Superclass, + private readonly expressionTraits: Traits, + ) {} extends< - Super extends AbstractClass + Super extends AbstractClass >( superclass: Super ) { return new TraitExpressionBuilder( - new TraitExpression( - superclass, - this.expression.ownTraits, - this.expression.allTraits, - ) + superclass, + this.expressionTraits, ) } expresses< - const Traits extends Trait[] - >( - ...traits: Traits - ): TraitExpressionBuilder< - Superclass, - [...OwnTraits, ...Traits], - [...AllTraits, ...SpreadSupertraits] - > { - return new TraitExpressionBuilder( - new TraitExpression( - this.expression.superclass, - [...this.expression.ownTraits, ...traits], - [...this.expression.allTraits, ...this.spreadSupertraits(traits)], - ) - ) - } - - private spreadSupertraits< - const Traits extends Trait< - TraitExpression[]>, + const T extends Trait< + TraitExpression< + typeof TraitExpression.NullSuperclass, + Trait[] + >, + any, any, any >[] >( - traits: Traits + ...traits: T ) { - return traits.flatMap(trait => [ - ...trait.supertraits.allTraits, - trait, - ]) as SpreadSupertraits + return new TraitExpressionBuilder( + this.expressionSuperclass, + + uniq([ + ...this.expressionTraits, + ...traits.flatMap(trait => [ + ...trait.superExpression.traits, + trait, + ]), + ]) as [...Traits, ...SpreadSupertraits], + ) } build() { - return this.expression as BuildTraitExpression + return new TraitExpression( + this.expressionSuperclass, + this.expressionTraits, + ) as BuildTraitExpression } then(fn: (expression: ReturnType) => V): V { return fn(this.build()) } + + buildAnyway() { + return new TraitExpression( + this.expressionSuperclass, + this.expressionTraits, + ) + } + + thenAnyway(fn: (expression: ReturnType) => V): V { + return fn(this.buildAnyway()) + } } -export const expression = new TraitExpressionBuilder(emptyTraitExpression) +export const expression = new TraitExpressionBuilder(TraitExpression.NullSuperclass, []) diff --git a/src/abstract.ts b/src/abstract.ts deleted file mode 100644 index c6502e4..0000000 --- a/src/abstract.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Opaque } from "type-fest" - - -export type AbstractTag = "@thilawyn/traitify-ts/Abstract" - -export function abstract< - Abstract extends {} = {} ->() { - return {} as Opaque -} diff --git a/src/lib.ts b/src/lib.ts index e7f6bb7..9426d7e 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -1,4 +1,4 @@ -export { trait, type Trait } from "./Trait" -export { Implements, type TraitExpression } from "./TraitExpression" +export { Trait, TraitClass, TraitConcreteClass, TraitInstance, TraitStaticMembers, TraitTuple } from "./Trait" +export { TraitBuilder, trait } from "./TraitBuilder" +export { Implements, ImplementsStatic, TraitExpression, TraitExpressionClass, TraitExpressionConcreteClass, TraitExpressionInstance, TraitExpressionStaticMembers } from "./TraitExpression" export { expression } from "./TraitExpressionBuilder" -export { abstract } from "./abstract" diff --git a/src/tests.ts b/src/tests.ts index 7773ed8..daf516b 100644 --- a/src/tests.ts +++ b/src/tests.ts @@ -1,67 +1,61 @@ -import { Trait, trait } from "./Trait" -import { Implements } from "./TraitExpression" +import { TraitClass } from "./Trait" +import { trait } from "./TraitBuilder" +import { Implements, ImplementsStatic, TraitExpressionClass } from "./TraitExpression" import { expression } from "./TraitExpressionBuilder" -import { abstract } from "./abstract" -const PrintsHelloOnNew = trait( - abstract(), - Super => class PrintsHelloOnNew extends Super { +const PrintsHelloOnNew = trait + .implement(Super => class PrintsHelloOnNew extends Super { static readonly isPrintsHelloOnNew = true constructor(...args: any[]) { super(...args) console.log("Hello!") } - }, -) -type PrintsHelloOnNewClass = Trait.Class + }) + .build() -const Identifiable = () => trait( - abstract<{ readonly id: ID }>(), - Super => class Identifiable extends Super { +type PrintsHelloOnNewClass = TraitClass + +const Identifiable = () => trait + .abstract(Super => class extends Super { + declare readonly id: ID + }) + .implement(Super => class Identifiable extends Super { equals(el: Identifiable) { return this.id === el.id } - }, -) + }) + .build() -const StatefulSubscription = trait( - abstract<{ - readonly isStatefulSubscription: true - readonly status: ( +const StatefulSubscription = trait + .abstract(Super => class extends Super { + declare readonly isStatefulSubscription: true + declare readonly status: ( { _tag: "awaitingPayment" } | { _tag: "active", activeSince: Date, expiresAt?: Date } | { _tag: "expired", expiredSince: Date } ) - }>(), + }) + .build() - Super => class StatefulSubscription extends Super {}, -) -type StatefulSubscriptionClass = Trait.Class +type StatefulSubscriptionClass = TraitClass const ActiveStatefulSubscription = expression .expresses(StatefulSubscription) .build() - .subtrait( - exp => { - interface IActiveStatefulSubscription extends Implements { - readonly isActiveStatefulSubscription: true - readonly status: { _tag: "active", activeSince: Date, expiresAt?: Date } - } - - return abstract() - }, - - Super => class ActiveStatefulSubscription extends Super {}, - ) - -type ActiveStatefulSubscriptionClass = Trait.Class + .subtrait() + .abstract(Super => class extends Super { + declare readonly isActiveStatefulSubscription: true + declare readonly status: { _tag: "active", activeSince: Date, expiresAt?: Date } + }) + .build() +type ActiveStatefulSubscriptionClass = TraitClass class TestSuperclass { // id: number = 69 - // static test = 69 + static test = 69 } const exp = expression @@ -75,7 +69,10 @@ const exp = expression .build() type Abs = Implements +type AbsStatic = ImplementsStatic +type ExpClass = TraitExpressionClass +@exp.implementsStatic class User extends exp.extends implements Implements { readonly isStatefulSubscription: true = true readonly isActiveStatefulSubscription: true = true @@ -84,3 +81,9 @@ class User extends exp.extends implements Implements { } console.log(new User()) + + +// type T = NonExtendableKeys<[ +// { prout: "gneugneu" }, +// { prout: string }, +// ]> diff --git a/src/util/extend.ts b/src/util/extend.ts index d675de5..1618656 100644 --- a/src/util/extend.ts +++ b/src/util/extend.ts @@ -1,25 +1,71 @@ -import { Call, ComposeLeft, Fn, Match, Tuples } from "hotscript" import { CommonKeys } from "." -type ExtendReducer = ( - Pick> extends Pick> - ? Omit> & Self - : never +// type ExtendReducer = ( +// Pick> extends Pick> +// ? Omit> & Self +// : never +// ) +// interface ExtendReducerFn extends Fn { +// return: ExtendReducer +// } +// export type ExtendFn = Tuples.Reduce + +// export type ExtendableFn = ComposeLeft<[ +// ExtendFn, +// Match<[ +// Match.With, +// Match.With, +// ]> +// ]> + + +// TODO: use OverrideProperties from type-fest? +export type Extend = ( + T extends [ + infer Super, + infer Self, + ...infer Rest extends object[], + ] + ? Pick> extends Pick> + ? Extend<[ + Omit> & Self, + ...Rest, + ]> + : never + : T extends [infer Self] + ? Self + : {} ) -interface ExtendReducerFn extends Fn { - return: ExtendReducer -} -export type ExtendFn = Tuples.Reduce -export type Extend = Call +export type Extendable = ( + T extends [ + infer Super, + infer Self, + ...infer Rest extends object[], + ] + ? Pick> extends Pick> + ? Extendable<[ + Omit> & Self, + ...Rest, + ]> + : false + : true +) - -export type ExtendableFn = ComposeLeft<[ - ExtendFn, - Match<[ - Match.With, - Match.With, - ]> -]> -export type Extendable = Call +export type NonExtendableKeys = ( + T extends [ + infer Super extends object, + infer Self extends object, + ...infer Rest extends object[], + ] + ? {[K in keyof Super & keyof Self]: Self[K] extends Super[K] + ? never + : K + }[keyof Super & keyof Self] + | NonExtendableKeys<[ + Super & Self, + ...Rest, + ]> + : void +) diff --git a/src/util/misc.ts b/src/util/misc.ts index 3e19396..175ddfd 100644 --- a/src/util/misc.ts +++ b/src/util/misc.ts @@ -1,5 +1,4 @@ -import { Fn } from "hotscript" -import { AbstractClass, Simplify } from "type-fest" +import { AbstractClass } from "type-fest" /** @@ -9,10 +8,6 @@ import { AbstractClass, Simplify } from "type-fest" */ export type CommonKeys = Extract -export interface SimplifyFn extends Fn { - return: Simplify -} - /** * Represents the static members of a class. * @template Class - A class extending AbstractClass. @@ -20,6 +15,3 @@ export interface SimplifyFn extends Fn { export type StaticMembers> = ( Omit ) -export interface StaticMembersFn extends Fn { - return: StaticMembers -}