1

我正在尝试包装类构造函数并使用类装饰器注入一些逻辑。在我尝试扩展包装类之前一切正常:扩展类在原型中没有方法。

    function logClass(Class) {
      // save a reference to the original constructor
      const _class = Class;
    
      // proxy constructor
      const proxy = function(...args) {
        const obj = new _class(...args);
        // ... add logic here
        return obj
      }
    
      // copy prototype so intanceof operator still works
      proxy.prototype = _class.prototype;
    
      // return proxy constructor (will override original)
      return proxy;
    }
    
    @logClass
    class Base {
      prop = 5;
      test() {
        console.log("test")
      }
    }
    
    class Extended extends Base {
      test2() {
        console.log("test2")
      }
    }
    
    var base = new Base()
    base.test()
    var ext = new Extended()
    console.log(ext.prop)
    ext.test()
    ext.test2() // TypeError: ext.test2 is not a function
4

1 回答 1

2

Okay so I tried to figure out what is "wrong" with your code, but I was not able to make it work because it didn't typecheck. So, as a last resort, I'm posting a partial answer of my attempt, which works (with some quirks) so I can help other users who are more savvy with TypeScript.

First of all, the quirks: class decorators in TS cannot modify the structure of a type, so if you wanted to, for example, add a method to the decorated class, you would be able to do it but you would have to eat up/suppress unavoidable type errors (TS2339) when calling those methods.

There is a work around for this in this other question: Typescript adding methods with decorator type does not exist, but you would lose this current clean syntax for decorators if you do this.

Now, my solution, taken more or less directly from the documentation:

function logClass<T extends { new(...args: any[]): {} }>(constructor: T) {
  return class extends constructor {
    constructor(...args: any[]) {
      super(args);
      // ...add programmatic logic here
      //    (`super` is the decorated class, of type `T`, here)
    }

    // ...add properties and methods here
    log(message: string) {        // EXAMPLE
      console.log(`${super.constructor.name} says: ${message}`);
    }
  }
}
    
@logClass
class Base {
  prop = 5;
  test() {
    console.log("test");
  }

  constructor() {}
}

class Extended extends Base {
  test2() {
    console.log("test2");
  }
}

var base = new Base();
base.test();
var ext = new Extended();
console.log(ext.prop);
//base.log("Hello");  // unavoidable type error TS2339
ext.test();
ext.test2();
于 2020-08-02T12:51:05.873 回答