0.1.2 #9
24
src/index.ts
24
src/index.ts
@@ -154,30 +154,6 @@ export function extendsAndExpresses<
|
||||
extend: C,
|
||||
...traits: Traits
|
||||
) {
|
||||
// Combine all static members of the traits
|
||||
type AllStaticMembers = UnionToIntersection<TraitClass<Traits[number]>>
|
||||
|
||||
// Combine all instance members of the traits
|
||||
type AllInstanceMembers = UnionToIntersection<TraitInstance<Traits[number]>>
|
||||
|
||||
// Extract common keys from all traits
|
||||
type CommonKeys = keyof AllStaticMembers & keyof AllInstanceMembers
|
||||
|
||||
// Exclude common keys from the static members of the last trait
|
||||
type StaticMembersWithoutCommon = Omit<AllStaticMembers, CommonKeys>
|
||||
|
||||
// Exclude common keys from the instance members of the last trait
|
||||
type InstanceMembersWithoutCommon = Omit<AllInstanceMembers, CommonKeys>
|
||||
|
||||
// Combine the instance members of the base class and the last trait
|
||||
type CombinedInstanceMembers = InstanceType<C> & InstanceMembersWithoutCommon
|
||||
|
||||
// Combine the static members of the base class and the last trait
|
||||
type CombinedStaticMembers = StaticMembers<C> & StaticMembersWithoutCommon
|
||||
|
||||
// Combine the instance and static members
|
||||
type CombinedMembers = CombinedInstanceMembers & CombinedStaticMembers
|
||||
|
||||
return traits.reduce(
|
||||
(previous, trait) => trait(previous),
|
||||
extend as Opaque<C, TraitApplierTag>,
|
||||
|
||||
104
src/tests.ts
104
src/tests.ts
@@ -1,5 +1,5 @@
|
||||
import { AbstractClass, Class, Simplify } from "type-fest"
|
||||
import { TraitInstance, expresses, extendsAndExpresses, trait } from "."
|
||||
import { AbstractClass } from "type-fest"
|
||||
import { expresses, extendsAndExpresses, trait } from "."
|
||||
|
||||
|
||||
const Identifiable = <ID>() =>
|
||||
@@ -71,56 +71,84 @@ console.log(user1)
|
||||
console.log(user1.equals(user1))
|
||||
|
||||
|
||||
abstract class TestTrait1 {
|
||||
abstract variable: number
|
||||
abstract member: {
|
||||
issou: string
|
||||
}
|
||||
abstract class Test1 {
|
||||
declare static name: string
|
||||
abstract name: string
|
||||
|
||||
declare createdAt: Date
|
||||
declare readonly status: (
|
||||
{ _tag: "awaitingPayment" } |
|
||||
{ _tag: "active", activeSince: Date, expiresAt?: Date } |
|
||||
{ _tag: "expired", expiredSince: Date }
|
||||
)
|
||||
}
|
||||
|
||||
abstract class TestTrait2 {
|
||||
abstract lol: BigInt
|
||||
abstract member: {
|
||||
issou: "gneugneu",
|
||||
adolf: string
|
||||
}
|
||||
class Test2 {
|
||||
declare readonly status: { _tag: "active", activeSince: Date, expiresAt?: Date }
|
||||
}
|
||||
|
||||
|
||||
type StaticMembers<C> = {
|
||||
[Key in keyof C as Key extends "prototype" ? never : Key]: C[Key]
|
||||
class Test3 {
|
||||
declare lol: 10n
|
||||
}
|
||||
|
||||
|
||||
type CommonKeys<A, B> = Extract<keyof A, keyof B>
|
||||
|
||||
type Extend2<Self, Parent> = (
|
||||
Pick<Self, CommonKeys<Self, Parent>> extends Pick<Parent, CommonKeys<Self, Parent>>
|
||||
? Omit<Parent, CommonKeys<Self, Parent>> & Self
|
||||
type Extend<T extends readonly any[]> = (
|
||||
T extends [infer Super, infer Self, ...infer Rest]
|
||||
? Pick<Self, CommonKeys<Self, Super>> extends Pick<Super, CommonKeys<Self, Super>>
|
||||
? Extend<[
|
||||
Omit<Super, CommonKeys<Self, Super>> & Self,
|
||||
...Rest,
|
||||
]>
|
||||
: never
|
||||
)
|
||||
|
||||
type ExtendN<Classes extends any[]> = (
|
||||
Classes extends [infer Parent, infer Self, ...infer Rest]
|
||||
? Extend2<Self, Parent> & ExtendN<Rest>
|
||||
: Classes extends [infer Self, ...infer Others]
|
||||
: T extends [infer Self]
|
||||
? Self
|
||||
: "Empty array"
|
||||
)
|
||||
|
||||
// type ExtendClass<
|
||||
// Self extends AbstractClass<any>,
|
||||
// Parent extends AbstractClass<any>,
|
||||
// > = (
|
||||
type ClassesInstances<Classes extends readonly any[]> = (
|
||||
Classes extends [infer Class, ...infer Rest]
|
||||
? Class extends AbstractClass<any>
|
||||
? [InstanceType<Class>, ...ClassesInstances<Rest>]
|
||||
: never
|
||||
: []
|
||||
)
|
||||
|
||||
// )
|
||||
type StaticMembers<Class extends AbstractClass<any>> = (
|
||||
Omit<Class, "prototype">
|
||||
)
|
||||
|
||||
type Test = Simplify<StaticMembers<typeof TestTrait2>>
|
||||
type MixedStaticTestTraits = ExtendN<[
|
||||
StaticMembers<typeof TestTrait2>,
|
||||
StaticMembers<typeof TestTrait1>,
|
||||
type ClassesStaticMembers<Classes extends readonly any[]> = (
|
||||
Classes extends [infer Class, ...infer Rest]
|
||||
? Class extends AbstractClass<any>
|
||||
? [StaticMembers<Class>, ...ClassesStaticMembers<Rest>]
|
||||
: never
|
||||
: []
|
||||
)
|
||||
|
||||
type ExtendClasses<Classes extends readonly AbstractClass<any>[]> = (
|
||||
AbstractClass<
|
||||
Extend<ClassesInstances<Classes>>
|
||||
> &
|
||||
Extend<ClassesStaticMembers<Classes>>
|
||||
)
|
||||
|
||||
|
||||
type MixedTestProto = ExtendClasses<[
|
||||
typeof Test1,
|
||||
typeof Test2,
|
||||
typeof Test3,
|
||||
]>
|
||||
|
||||
type MixedTestTraitsProto = Class<
|
||||
Extend2<TestTrait2, TestTrait1>,
|
||||
any[]
|
||||
> & Extend2<StaticMembers<typeof TestTrait2>, StaticMembers<typeof TestTrait1>>
|
||||
declare const MixedTestProto: MixedTestProto
|
||||
|
||||
class MixedTest extends MixedTestProto {}
|
||||
|
||||
MixedTest.prototype
|
||||
new MixedTest().name
|
||||
|
||||
// type MixedTestTraitsProto = Class<
|
||||
// Extend2<TestTrait2, TestTrait1>,
|
||||
// any[]
|
||||
// > & Extend2<StaticMembers<typeof TestTrait2>, StaticMembers<typeof TestTrait1>>
|
||||
|
||||
Reference in New Issue
Block a user