使用Decorator获取已实现接口的列表

时间:2015-05-12 10:39:12

标签: typescript aurelia babeljs typescript1.5 ecmascript-7

您是否知道是否可以使用装饰器获取类实现的接口数组:

interface IWarrior {
  // ...
}

interface INinja {
  // ...
}

所以如果我这样做:

@somedecorator
class Ninja implements INinja, IWarrior {
 // ...
}

在运行时,Ninja会有一个注释,其中包含["INinja", "IWarrior"]

由于

2 个答案:

答案 0 :(得分:4)

目前,类型仅在开发和编译期间使用。类型信息不会以任何方式转换为已编译的JavaScript代码。但是你可以将字符串列表传递给装饰器参数,如下所示:

interface IWarrior {
  // ...
}

interface INinja {
  // ...
}


interface Function {
    interfacesList: string[];
}

@interfaces(["INinja", "IWarrior"])
class Ninja implements INinja, IWarrior {

}

function interfaces(list: string[]) {
    return (target: any) => {
        target.interfacesList = list; 
        return target;
    }
}

console.log(Ninja.interfacesList);

答案 1 :(得分:2)

由于在编译时抛弃了有关接口的所有信息,因此无法实现。 somedecorator的实现无法访问编译器抛弃的信息。

可以将接口名称作为字符串传递给装饰器,但这并不是很有用,因为接口提供的所有信息都将在运行时消失。

关于实现装饰器的一个很好的堆栈溢出问题:

How to implement a typescript decorator?

编辑:

因此,经过一段时间的研究,你的问题的答案仍然没有。有两个原因:

  1. 编译时(有或没有装饰器)
  2. 后,无法访问有关接口的信息
  3. 装饰器无法访问类的继承属性。
  4. 用一些例子来说明这一点:

    function myDecorator() {
        // do something here.. 
    }
    
    interface INamed { name: string; }
    
    interface ICounted { getCount() : number; }
    
    interface ISomeOtherInterface { a: number; }
    
    class SomeClass {
        constructor() { }
    }
    
    class Foo implements INamed {
        constructor(public name: string) { }    
    }
    
    @myDecorator
    class Bar extends Foo implements ICounted {
    
        private _count: number;
        getCount() : number { return this._count; }
    
        constructor(name: string, count: number, public someProp: ISomeOtherInterface, public someClass: SomeClass) {
            super(name);
            this._count = count;
        }
    }
    

    这将导致编译代码(带有--emitDecoratorMetadata标志):

    function myDecorator() {
        // do something here.. 
    }
    var SomeClass = (function () {
        function SomeClass() {
        }
        return SomeClass;
    })();
    var Foo = (function () {
        function Foo(name) {
            this.name = name;
        }
        return Foo;
    })();
    var Bar = (function (_super) {
        __extends(Bar, _super);
        function Bar(name, count, someProp, someClass) {
            _super.call(this, name);
            this.someProp = someProp;
            this.someClass = someClass;
            this._count = count;
        }
        Bar.prototype.getCount = function () { return this._count; };
        Bar = __decorate([
            myDecorator, 
            __metadata('design:paramtypes', [String, Number, Object, SomeClass])
        ], Bar);
        return Bar;
    })(Foo);
    

    装饰器中可用的任何信息(自己的类除外)都包含在__decorate部分中:

    __decorate([
            myDecorator, 
            __metadata('design:paramtypes', [String, Number, Object, SomeClass])
        ], Bar);
    

    现在看来,没有关于继承或接口的信息传递给装饰器。类的所有装饰器都是装饰构造函数。这可能不会改变,当然也不会改变接口(因为关于它们的所有信息都会在编译时被丢弃)。

    我们可以在__metadata的类型数组中获取String,Number和类SomeClass(构造函数参数)的类型信息。但是接口ISomeOtherInterface被报告为Object,这是因为在编译的javascript中没有保留有关typescript接口的信息。所以我们可以获得的最佳信息是Object。

    您可以使用类似https://github.com/rbuckton/ReflectDecorators的内容来更好地使用装饰器,但您仍然只能访问__decorate和__metadata中的信息。

    总结一下。在装饰器中没有关于类的继承或接口的信息。接口可能永远不可用于装饰器(或编译代码中的任何其他位置)。