composition/source/composition.ts
2025-03-03 06:15:30 +00:00

58 lines
1.4 KiB
TypeScript

/**
* creates an object, which has all the methods of a class instance, but as
* plain functions (required for composition)
*/
function dullCopy<X>(instance: X): X {
const methodBlacklist: Set<string> = new Set<string>([
"__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<string> = 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, Y>(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));
}