architectuur - Typescript methode-decorator voor afgeleide klasse
Mijn verwachting voor 'h.collection' is [[ 'a', alpha], ['b', beta]], en voor 'w.collection' is [[ 'a', alpha], ['c', gama]].
Maar zowel Greeter, Hello als World delen gewoon dezelfde 'collectie', toch?
Dus, welke codewijzigingen moet ik aanbrengen?
function alias(alias: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
let func = target[propertyKey];
func.alias = alias;
if (!target.collection) {
target.collection = new Map();
}
target.collection.set(alias, func);
};
}
abstract class Greeter {
public collection: Map<string, Function>;
@alias('a')
alpha(){}
}
class Hello extends Greeter {
@alias('b')
beta(){}
}
class World extends Greeter {
@alias('c')
gama(){}
}
let h = new Hello();
let w = new World();
console.log(h.collection);
console.log(w.collection);
Antwoord #1
Hier is mijn onhandige oplossing als tijdelijke oplossing. Dit is de meest elegante manier die ik kan bedenken.
function alias(alias: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
let className: string = target.constructor.name;
let func = descriptor.value;
func.alias = alias;
target.shadowCollections = target.shadowCollections || {}
let shadowCollections = target.shadowCollections;
shadowCollections[className] = shadowCollections[className] || new Map();
let collection: Map<string, Function> = shadowCollections[className];
collection.set(alias, func);
};
}
function fix<T extends { new(...args: any[]): {} }>(ctor: T) {
let all: [string, Function][] = [];
function* getClassNames(_ctor: T) {
while (_ctor && _ctor.name) {
yield _ctor.name;
_ctor = Object.getPrototypeOf(_ctor);
}
}
for (let className of getClassNames(ctor)) {
let current: Map<string, Function> = ctor.prototype.shadowCollections[className];
all.push(...current);
}
all.sort(([a,], [b,]) => a < b ? -1 : (a > b ? 1 : 0));
delete ctor.prototype.shadowCollections;
return class extends ctor {
_collection = new Map(all);
}
}
abstract class Greeter {
protected _collection: Map<string, Function>;
public get collection(): Map<string, Function> {
return this._collection;
}
@alias('a')
alpha() { }
}
@fix
class Hello extends Greeter {
@alias('b')
beta() { }
}
@fix
class World extends Greeter {
@alias('c')
gama() { }
}
let h = new Hello();
let w = new World();
console.log(h.collection);
console.log(w.collection);
