为什么无法通过装饰添加方法

时间:2018-03-22 12:05:39

标签: javascript typescript

假设我有一个指令装饰器,它向其名为factory的目标添加一个静态方法:

function Directive<T extends { new (...args: any[]): {} }>(constructor: T) {
  return class extends constructor {
    static factory(...args): ng.IDirectiveFactory {
      const c: any = () => {
        return constructor.apply(this, args);
      };
      c.prototype = constructor.prototype;
      return new c(...args);
    }
  };
}

我还通过界面添加类型:

interface BaseDirective extends ng.IDirective {
  factory(): ng.IDirectiveFactory;
}

为什么我的班级声明:

@Directive
class FocusedDirective implements BaseDirective {....

我得到Class 'FocusedDirective' incorrectly implements interface 'BaseDirective'. Property 'factory' is missing in type 'FocusedDirective'.

我错误地期望@Directive为我添加这个遗失的财产?

2 个答案:

答案 0 :(得分:2)

装饰者不能改变类的类型,你可以将你的装饰器作为一个函数调用并存储将包含该方法的新类,并使用新类而不是原来的类:

 const FocusedDirectiveWithDirective = Directive(FocusedDirective);

您可以使用类表达式完全取消中间类:

const FocusedDirective = Directive(class implements BaseDirective{

});

答案 1 :(得分:1)

你有两个问题。第一个与装饰器几乎没有关系:factory是实现中的静态方法,但在接口中是常规方法:

interface BaseDirective  {
    factory(): ng.IDirectiveFactory;
}

这对你来说是个问题。现在我要将实现转换为常规方法,因为它更容易实现。

function Directive<T extends { new(...args: any[]): {} }>(constructor: T) {
    return class extends constructor {
        factory(...args: any[]): ng.IDirectiveFactory {
            const c: any = () => {
                return constructor.apply(this, args);
            };
            c.prototype = constructor.prototype;
            return new c(...args);
        }
    };
}

第二个问题:装饰者不会以你期望的方式改变类签名。这是一个oft-requested feature,并且有一些有趣的问题,为什么它不是一个简单的问题需要解决。重要的是,要弄清楚如何支持让类的实现引用变异类型并不容易。在您的情况下:{....内的内容是否会知道factory()?大多数人似乎都会期待它,但尚未应用装饰器。

解决方法是根本不使用装饰器语法,而是使用装饰器函数作为常规函数来创建新类。语法如下所示:

class FocusedDirective extends Directive(class {

    // any impl that doesn't rely on factory
    prop: string = "hey";
    foo() {
        this.prop; // okay
        // this.factory(); // not okay
    }

}) implements BaseDirective {

    // any impl that relies on factory
    bar() {
        this.prop; // okay
        this.foo(); // okay
        this.factory(); // okay
    }

}

这也解决了“实现了解装饰器”的问题,因为装饰器功能中的东西没有,而外面的东西也是如此,如上所示。

回到静态/实例问题。如果要在类的静态方面强制实施约束,则不能通过让类实现任何内容来实现。相反,您需要在类构造函数本身上强制执行静态方面。像这样:

interface BaseDirective {
  // any actual instance stuff here
}

interface BaseDirectiveConstructor {
    new(...args: any[]): BaseDirective;
    factory(): ng.IDirectiveFactory;
}

class FocusedDirective extends Directive(class {
   // impl without BaseDirectiveConstructor
}) implements BaseDirective {
    // impl with BaseDirectiveConstructor
    bar() {
        FocusedDirective.factory(); // okay
    }
}

function ensureBaseDirectiveConstructor<T extends BaseDirectiveConstructor>(t: T): void {}
ensureBaseDirectiveConstructor(FocusedDirective);

ensureBaseDirectiveConstructor()函数确保FocusedDirective类构造函数具有正确类型的静态factory()方法。如果你没有实现静态方面,那就是你会看到错误的地方。

好的,希望有所帮助。祝你好运。