export interface Mixin { new (...args: any[]): C1 & C2; } export type Constructor = new (...args: any[]) => T; function assignProps(dstObj: any, srcObj: any) { Object.getOwnPropertyNames(srcObj).forEach(name => { dstObj[name] = srcObj[name]; }); } function getPrototypeChain(baseProto: any) { let res: any[] = []; while (true) { const proto = Object.getPrototypeOf(baseProto); if (!proto || proto === Object.prototype) { break; } res.push(proto); baseProto = proto; } res.reverse(); return res; } export function mix(baseClass: Constructor, mixClass: Constructor) { class NewClass extends (baseClass as Constructor<{}>) { constructor (...args: any[]) { super(...args); } } [baseClass, mixClass].forEach(baseCtor => { const protos = [baseCtor.prototype, ...getPrototypeChain(baseCtor.prototype)]; protos.forEach(proto => assignProps(NewClass.prototype, proto)); }); return NewClass as any as Mixin; } export function mixSome(...classes: Constructor[]) { let result = classes[0]; classes.slice(1).forEach(ctor => { result = mix(result, ctor); }); return result; }