【问题标题】:TypeScript 1.5, reflection and decoratorTypeScript 1.5,反射和装饰器
【发布时间】:2015-08-19 21:46:55
【问题描述】:

我想知道是否可以使用反射,尤其是关于装饰器、属性、参数或方法的类反射?

这可以使用反射器来获取装饰器中使用的信息吗?

如果可能,我们该怎么做? 否则,我们为什么不能这样做?

编辑:

我有一个应用程序,我在其中使用装饰器将数据从 serviceRegistry 注入到名为 @Inject 的装饰器。

在这个应用程序中,我手动填写了一个简单的服务注册表,例如:

serviceRegistry.push(MyClass1)
serviceRegistry.push(MyClass2)
...
serviceRegistry.push(MyClass100)

目的是能够在运行时使用带有@ToInject 注解修饰的类填充此服务注册表。

这将允许我避免手动填写此注册表,并简单地自动执行此操作。

感谢提前

【问题讨论】:

  • Here 就是一个例子。我没有让它与刚刚报告语法错误的 PhantomJS 2 一起工作。
  • 你的最终目标是什么?如果你能提供一个例子,这将有助于回答你的问题。

标签: typescript typescript1.5


【解决方案1】:

我刚刚发布了一个增强版的 TypeScript 编译器,它提供了完整的反射功能:

  • 运行时的类/接口元数据
  • 从元数据对象实例化类
  • 从类构造函数中检索元数据

您可以查看here

【讨论】:

  • TypeScript 社区长期以来一直在寻求反射功能。这是问题的答案。没有其他库/编译器版本可以处理这些要求。看看它。此外,我说“我刚刚发布......”所以很明显这是我拥有的一个项目。
  • 我的意思是你不应该在没有调整你的答案并包括适当的例子的情况下,在没有细节的情况下复制完全相同的答案。
【解决方案2】:

您可以通过导入 reflect-metadata 包来使用反射。

import 'reflect-metadata';

将它与 TypeScript 1.5 一起使用,并将编译器标志 emitDecoratorMetadata 设置为 true。不要忘记包括对reflect-metadata.d.ts 的引用。

您需要实现自己的装饰器:

// declare property decorator
function logType(target : any, key : string) {
  var t = Reflect.getMetadata("design:type", target, key);
  console.log(`${key} type: ${t.name}`);
}

class Demo{ 
  @logType // apply property decorator
  public attr1 : string;
}

它将登录控制台:

attr1 type: String

另一个例子:

// declare parameter decorator
function logParamTypes(target : any, key : string) {
  var types = Reflect.getMetadata("design:paramtypes", target, key);
  var s = types.map(a => a.name).join();
  console.log(`${key} param types: ${s}`);
}  

class Foo {}
interface IFoo {}

class Demo{ 
  @logParameters // apply parameter decorator
  doSomething(
    param1 : string,
    param2 : number,
    param3 : Foo,
    param4 : { test : string },
    param5 : IFoo,
    param6 : Function,
    param7 : (a : number) => void,
  ) : number { 
      return 1
  }
}

它将登录控制台:

doSomething param types: String, Number, Foo, Object, Object, Function, Function

注意接口IFoo 和对象字面量{ test : string} 被序列化为Object。序列化规则为:

  • number 序列化为Number
  • string 序列化为String
  • boolean 序列化为Boolean
  • any 序列化为Object
  • void 序列化为 undefined
  • Array 序列化为 Array
  • 如果是Tuple,序列化为Array
  • 如果 class 将其序列化为类构造函数
  • 如果Enum 将其序列化为Number
  • 如果有至少一个调用签名,序列化为Function
  • 否则序列化为Object(包括接口)

接口和对象字面量将来可能会通过复杂类型序列化进行序列化,但此功能目前不可用。

您还可以使用以下方法获取函数的返回类型:

Reflect.getMetadata("design:returntype", target, key);

如果您需要有关装饰器的更多信息,可以阅读:Decorators & metadata reflection in TypeScript: From Novice to Expert

【讨论】:

  • 您能否详细说明“不要忘记包括对 reflect-metadata.d.ts 的引用。”?
  • Reflect-metadata 在 npm 模块中包含 .d.ts 文件。当我写这个答案时,需要在 dts 文件中使用/// <reference path="">。今天,如果您使用的是 TS >= 2.0,则无需这样做。
  • 这是另一个使用装饰器的例子stackoverflow.com/questions/38085883/…
猜你喜欢
  • 2018-11-19
  • 2022-01-17
  • 1970-01-01
  • 2019-07-29
  • 2020-01-16
  • 2018-07-21
  • 2018-06-08
  • 2019-02-23
  • 2017-11-15
相关资源
最近更新 更多