angular - 装饰器何时以及如何应用于 @Angular 包中的装饰类

标签 angular typescript decorator reflect-metadata

如果我在类中使用装饰器,则在导入类时会评估装饰器。这是一个小例子:

@NgModule({ ... })
export class BModule { ... }

转译为:

var BModule = (function () {
    function BModule() {
    }
    BModule = __decorate([  <---------- decorators are applied here
        core_1.NgModule({...})
    ], BModule);
    return BModule;
}());
exports.BModule = BModule;

但是,当在 @angular 包中应用模块或任何其他装饰器时,输出如下:

var HttpClientModule = (function () {
    function HttpClientModule() {
    }
    return HttpClientModule;
}());
HttpClientModule.decorators = [
    { type: _angular_core.NgModule, args: [{ ... },] },
];

如您所见,这里没有应用装饰器。它们只是保存在装饰器属性中。为什么它与我的代码不同?

我问的原因是,当导入我的装饰类时,我希望它应用装饰器,因此可以使用 Reflect :

const providers = Reflect.getOwnMetadata('annotations', BModule);

但是,对于 @angular 包中的修饰类来说,这种方式不起作用。

最佳答案

当 anglat 解析注释时,它有 three options :

1) 直接 API

// Prefer the direct API.
if ((<any>typeOrFunc).annotations && (<any>typeOrFunc).annotations !== parentCtor.annotations) {
  let annotations = (<any>typeOrFunc).annotations;
  if (typeof annotations === 'function' && annotations.annotations) {
    annotations = annotations.annotations;
  }
  return annotations;
}

我们在ES5中编写代码时通常会使用这个API

MyComponent.annotations = [
  new ng.Component({...})
]

2) tsickle API

// API of tsickle for lowering decorators to properties on the class.
if ((<any>typeOrFunc).decorators && (<any>typeOrFunc).decorators !== parentCtor.decorators) {
  return convertTsickleDecoratorIntoMetadata((<any>typeOrFunc).decorators);
}

通过这种方式,Angular 可以从 @Angular/(core|material...) 库中读取注释。 Angular 以这种方式编译库,因为它有助于优化包。例如,我们不需要发送像 _decorate、__metadata 这样的装饰器助手,并且代码将执行得更快。

对于该 Angular ,在通过使用 --importHelpers 选项运行 tsc 来构建库时使用 tslib https://github.com/angular/angular/blob/master/build.sh#L127 .

Angular Material 也能做同样的事情 https://github.com/angular/material2/blob/master/tools/package-tools/rollup-helpers.ts#L9-L11

// Import tslib rather than having TypeScript output its helpers multiple times.
// See https://github.com/Microsoft/tslib
'tslib': 'tslib',

3)使用反射

// API for metadata created by invoking the decorators.
if (this._reflect && this._reflect.getOwnMetadata) {
  return this._reflect.getOwnMetadata('annotations', typeOrFunc);
}

当我们使用 typescript 发出的元数据时,会使用此 API

为了确保您能够正确获取元数据,您可以考虑使用如下函数:

declare let Reflect: any;
function getAnnotations(typeOrFunc: Type<any>): any[]|null {
  // Prefer the direct API.
  if ((<any>typeOrFunc).annotations) {
    let annotations = (<any>typeOrFunc).annotations;
    if (typeof annotations === 'function' && annotations.annotations) {
      annotations = annotations.annotations;
    }
    return annotations;
  }

  // API of tsickle for lowering decorators to properties on the class.
  if ((<any>typeOrFunc).decorators) {
    return convertTsickleDecoratorIntoMetadata((<any>typeOrFunc).decorators);
  }

  // API for metadata created by invoking the decorators.
  if (Reflect && Reflect.getOwnMetadata) {
    return Reflect.getOwnMetadata('annotations', typeOrFunc);
  }
  return null;
}

function convertTsickleDecoratorIntoMetadata(decoratorInvocations: any[]): any[] {
  if (!decoratorInvocations) {
    return [];
  }
  return decoratorInvocations.map(decoratorInvocation => {
    const decoratorType = decoratorInvocation.type;
    const annotationCls = decoratorType.annotationCls;
    const annotationArgs = decoratorInvocation.args ? decoratorInvocation.args : [];
    return new annotationCls(...annotationArgs);
  });
}


const annotations = getAnnotations(AppModule);

更新:

通过调用装饰器创建的元数据的 API 在 5.0.0-beta.4 中已更改

const ANNOTATIONS = '__annotations__';

// API for metadata created by invoking the decorators.

if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) {
   return (typeOrFunc as any)[ANNOTATIONS];
}
return null;

关于angular - 装饰器何时以及如何应用于 @Angular 包中的装饰类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45274539/

相关文章:

angular - Angular 2 中 Zone.js 的用途是什么

typescript - OpenAPI 3.1 与 openapi-generator-cli typescript-fetch : JsonParseException: Unrecognized token 'openapi' : was expecting (JSON String, ...)

Python3有条件地装饰?

javascript - 折线图(google chart)自定义标签

django - 使用带有 Django CSRF 保护的 angular2 http 请求的正确方法是什么?

json - 如何使用 'require'在NestJS Controller 中导入JSON?

Python 装饰器? - 有人可以解释一下吗?

Angular 2.0.0 Metadata_resolver 奇怪的行为

html - 如何动态合并表格中的单元格

python - 装饰一个产生的函数