How to properly wrap constructors with decorators in TypeScript

后端 未结 5 2000
猫巷女王i
猫巷女王i 2020-12-28 08:32

The process of wrapping a class with a decorator causes superclasses to be unable to access that classes\' properties. Why?

I have some code that:

  1. Crea
5条回答
  •  猫巷女王i
    2020-12-28 09:12

    The comments in the other answers complain that code doesn't work.
    Actually, it works, but not in jsFiddle...
    It is an issue with the code generation in jsFiddle (perhaps using an obsolete version of TypeScript).
    The code above works with TypeScript 2.7.2 (run with Node).

    So this is basically the code in pablorsk's answer (except there is no need to return the instance), I just added full types to please a stricter TSLint...

    function logClass(): any {
        type Ctor = new (...args: any[]) => T;
        return (target: T): Ctor => {
            // Save a reference to the original constructor
            const Original = target;
    
            // the new constructor behaviour
            let decoratedConstructor: any = function (...args: any[]): void {
                console.log("Before construction:", Original);
                Original.apply(this, args);
                console.log("After construction");
            };
    
            // Copy prototype so intanceof operator still works
            decoratedConstructor.prototype = Original.prototype;
            // Copy static members too
            Object.keys(Original).forEach((name: string) => { decoratedConstructor[name] = (Original)[name]; });
    
            // Return new constructor (will override original)
            return decoratedConstructor;
        };
    }
    
    @logClass()
    class Base {
        prop = 5;
        constructor(value: number) {
            console.log("Base constructor", value);
            this.prop *= value;
        }
        foo() { console.log("Foo", this.prop); }
        static s() { console.log("Static s"); }
    }
    
    class Extended extends Base {
        constructor(init: number) {
            super(init);
            console.log("Extended constructor", init);
        }
        bar() { console.log("Bar", this.prop); }
    }
    
    const b = new Base(2);
    console.log("Base", b instanceof Base);
    b.foo();
    Base.s();
    
    const e = new Extended(5);
    console.log("Extended", e instanceof Base, e instanceof Extended);
    e.bar();
    

    [EDIT] Also added a line copying static members, otherwise decorated class throws an error when calling the static method.

提交回复
热议问题