Typescript 中如何编译装饰器(注解)?

Posted

技术标签:

【中文标题】Typescript 中如何编译装饰器(注解)?【英文标题】:How are decorators (annotations) compiled in Typescript? 【发布时间】:2016-04-27 13:32:15 【问题描述】:

在 Angular 2 中,我可以创建一个组件,如下所示:

import Component, Template from 'angular2/angular2'

@Component(
  selector: 'my-component'
)
@View(
  inline: "<div>Hello my name is name</div>"
)
export class MyComponent 
  constructor() 
    this.name = 'Max'
  
  sayMyName() 
    console.log('My name is', this.name)
  

(来源:http://blog.ionic.io/angular-2-series-components/)

然后将其编译为常规 ES5。

我的问题分为两部分:

    这些装饰器是 Angular 特有的。它们是如何定义的? 如何定义自己的装饰器?

【问题讨论】:

见blog.wolksoftware.com/…。这个问题似乎也与***.com/questions/34465214/… 非常相似 那是一篇不错的博文。 【参考方案1】:

事实上,您应该调用“注解”装饰器,因为它略有不同;-) 它们允许装饰对象。这篇博文可以在这里提供更多提示:http://blog.thoughtram.io/angular/2015/05/03/the-difference-between-annotations-and-decorators.html

所以装饰器并不是 Angular 特有的。有一个 ES7 提案,TypeScript 语言本身也支持它们。这可以与reflect-metadata 库(它包含在angular2-polyfills.js 文件中)结合使用来设置和获取元素的元数据。

类装饰器

export function MyClassDecorator(value: string) 
  return function (target: Function) 
    Reflect.defineMetadata("MyClassDecorator", value, target);
  


@Component( ... )
@MyClassDecorator("my metadata")
export class AppComponent 
  constructor() 
    let decoratorValue: string
      = Reflect.getMetadata("MyClassDecorator", this.constructor);
  

函数装饰器

export function log(target: Object,
                propertyKey: string,
                descriptor: TypedPropertyDescriptor<any>) 
  var originalMethod = descriptor.value;

  descriptor.value = function(...args: any[]) 
    console.log("The method args are: " + JSON.stringify(args));
    var result = originalMethod.apply(this, args);
    console.log("The return value is: " + result);
    return result;
  ;

  return descriptor;


export class AppComponent 
  constructor()  

  @MyMethodDecorator
  getMessage() 
    return 'test';
  

参数装饰器

export function MyParameterDecorator(param1) 
  return function(target: any, methodKey: string | symbol,
                  parameterIndex: number) 
    (...)
  ;

类属性装饰器

export function MyPropertyDecorator(target: any,
        propertyKey: string | symbol) 
  (...)

所以一般来说一个装饰器对应一个函数。如果不使用参数,则无需返回包装。如果你想为装饰器使用参数,你需要一个额外的函数来获取参数并返回实际的装饰器:

// In the case of a parameter decorator
// myMethod(@MyDecoratorWithoutParameter someParam)  ... 
export function MyDecoratorWithoutParameter(target: any,
    propertyKey: string | symbol, parameterIndex: number) 
  console.log('decorator called');


// myMethod(@MyDecoratorWithParameter('test') someParam)  ... 
export function MyDecoratorWithParameter(param1) 
  // param1 contains 'test'
  return function(target: any, propertyKey: string | symbol,
                  parameterIndex: number) 
    console.log('decorator called');
  ;

这是与我的示例对应的 plunkr:https://plnkr.co/edit/0VBthTEuIAsHJjn1WaAX?p=preview。

以下链接可以为您提供有关 TypeScript 的更多详细信息:

How to implement a typescript decorator? How to avoid hard coded this? in Decorators http://blogs.msdn.com/b/typescript/archive/2015/04/30/announcing-typescript-1-5-beta.aspx

希望对你有帮助 蒂埃里

【讨论】:

以上是关于Typescript 中如何编译装饰器(注解)?的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript 和 React:如何重载高阶组件/装饰器?

LayaBox---TypeScript---装饰器

Typescript:使用装饰器时的类型推断

对 TypeScript 使用 @Prop 装饰器 - 编译器在要求初始化 prop 时出错

TypeScript学习笔记:装饰器(Decorators)

TypeScript 装饰器的执行原理