/** * creates an object, which has all the methods of a class instance, but as * plain functions (required for composition) */ function dullCopy(instance: X): X { const methodBlacklist: Set = new Set([ "__defineGetter__", "__defineSetter__", "__lookupGetter__", "__lookupSetter__", "__proto__", "constructor", "isPrototypeOf", "hasOwnProperty", "propertyIsEnumerable", "valueOf", "toString", "toLocaleString", ]); const result = {}; // attributes { for (const [name, value] of Object.entries(instance)) { result[name] = value; } } // methods { const methodNames: Array = Object.getOwnPropertyNames(instance["__proto__"]); for (const methodName of methodNames) { if (! methodBlacklist.has(methodName)) { result[methodName] = function (...methodArgs) { return instance[methodName].apply(instance, methodArgs); }; } } } return (result as X); } /** * creates a combination of two class instances, forming a new object with the * methods of both operands (as plain functions) */ function compose(x: X, y: Y): (X & Y) { const result = {}; for (const object of [x, y]) { for (const [name, implementation] of Object.entries(dullCopy(object))) { if (name in result) { process.stderr.write("[warn] overwriting method '" + name + "'\n"); } result[name] = implementation; } } return (result as (X & Y)); }