装饰器何时以及如何应用到 @angular 包中的装饰类
Posted
技术标签:
【中文标题】装饰器何时以及如何应用到 @angular 包中的装饰类【英文标题】:When and how s decorator applied to the decorated classes from the @angular packages 【发布时间】:2017-12-29 16:22:37 【问题描述】:如果我在我的类中使用装饰器,则在导入类时会评估装饰器。这是一个小例子:
@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
包中的装饰类。
【问题讨论】:
【参考方案1】:当 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 从@angular/(core|material...)
库中读取注释。 Angular 以这种方式编译库是因为它有助于优化包。例如,我们不需要像_decorate, __metadata
那样发送装饰器助手,代码会执行得更快。
对于该角度使用tslib
构建库时通过运行带有--importHelpers
选项https://github.com/angular/angular/blob/master/build.sh#L127 的tsc。
Angular 材质做同样的事情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;
【讨论】:
感谢您的回答)也许可以添加一些指向源的链接?此外,似乎我们可以依赖decorators
的存在,直到支持 tsickle
,对吗?我展示了需要decorators
属性的解决方案here
我认为一旦浏览器原生支持 Reflect 和 Decorators,前两个选项将不被支持
添加了链接。我认为在这种情况下我们可以使用 Reflect 作为后备
@Maximus 以防我们不知道以哪种格式构建库。这就是 Angular 使用所有三个选项的原因
很遗憾,Reflect 似乎没有从 .decorators
属性中检索元数据以上是关于装饰器何时以及如何应用到 @angular 包中的装饰类的主要内容,如果未能解决你的问题,请参考以下文章
Angular 中的 @Directive 与 @Component
Angular 中的 @Directive 与 @Component
Angular 中的 @Directive 与 @Component
Angular 中的 @Directive 与 @Component