在 Typescript 中为接口创建混合

Create a mixin for interfaces in Typescript

interface IBase {
  baseProp?: string;
}

class Base implements IBase {
  baseProp: string = "baseProp";
}

type AnyClass<T> = new () => T;

interface IClass1 extends IBase {
  class1Prop?: string;
}

const Class1Mixin = (MixedClasses: AnyClass<any>): AnyClass<IClass1> =>
  class extends MixedClasses implements IClass1 {
    class1Prop: string = "class1Prop";
  };

interface IClass2 extends IBase {
  class2Prop?: string;
}

const Class2Mixin = (MixedClasses: AnyClass<any>): AnyClass<IClass2> =>
  class extends MixedClasses implements IClass2 {
    class2Prop: string = "class2Prop";
  };

// Mix classes
const mix = <T>(...extensions: Array<(anyClass: any) => AnyClass<T>>) => {
  let Composition = Base as AnyClass<IBase>;

  for (const ext of extensions) {
    Composition = ext(Composition);
  }
  return Composition as AnyClass<T>;
};

// Here can be any number of classes
const Mixed = mix(Class1Mixin, Class2Mixin);
const mixedInit = new Mixed();
// Now mixedInit is IBase & ICLass1
// and I need that it will be IBase & ICLass1 & ICLass2

console.log(mixedInit.baseProp, mixedInit.class1Prop, mixedInit.class2Prop);

我有一个函数可以将任意数量的 classes 与 Base class 混合在一起。但是我不能混用这些classes 的接口。请告诉我如何改进混合函数类型来做到这一点?

下面的代码是solution.The这个解决方案的实质是联合型转交集type.You关于联合型转交集的问题可以看

interface IBase {
  baseProp?: string;
}

class Base implements IBase {
  baseProp: string = "baseProp";
}

type AnyClass<T> = new () => T;

interface IClass1 extends IBase {
  class1Prop?: string;
}

const Class1Mixin = (MixedClasses: AnyClass<any>): AnyClass<IClass1> =>
  class extends MixedClasses implements IClass1 {
    class1Prop: string = "class1Prop";
  };

interface IClass2 extends IBase {
  class2Prop?: string;
}

const Class2Mixin = (MixedClasses: AnyClass<any>): AnyClass<IClass2> =>
  class extends MixedClasses implements IClass2 {
    class2Prop: string = "class2Prop";
  };


type UnionToIntersection<U> = 
  (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never

// Modified Mix classes
const mix = <T extends Array<(MixedClasses: AnyClass<any>) => AnyClass<any>>>(...extensions: T): AnyClass<UnionToIntersection<InstanceType<ReturnType<T[number]>>>> => {
  let Composition = Base as AnyClass<IBase>;

  for (const ext of extensions) {
    Composition = ext(Composition);
  }
  return Composition as any;
};

const Mixed = mix(Class1Mixin, Class2Mixin);
const mixedInit = new Mixed();
// Now mixedInit is ICLass1 & ICLass2

console.log(mixedInit.baseProp, mixedInit.class1Prop, mixedInit.class2Prop);