Zoeken op website

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);