如果我在我的类中使用装饰器,则在导入类时会评估装饰器.这是一个小例子:
- @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: [{ ... },] },];
如您所见,装饰器不适用于此处.它们只保存在decorators属性中.为什么它与我的代码不同?
我问的原因是,在导入我的装饰类时,我希望它应用了装饰器,因此使用Reflect是可能的:
- const providers = Reflect.getOwnMetadata('annotations',BModule);
但是,对于@angular包中的装饰类,它不能以这种方式工作.
当angulat解析注释时,它有
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 /(core | material …)库中读取注释. Angular以这种方式编译库,因为它有助于优化bundle.例如,我们不需要像_decorate,__ Metadata一样运送装饰器助手,代码将更快地执行.
对于该角度使用tslib在构建库时通过使用–importHelpers选项https://github.com/angular/angular/blob/master/build.sh#L127运行tsc.
角度材料做同样的事情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)使用反射
当我们使用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;