首先说下作用:这个函数用来创建Decorator,如
Injectable
export const Injectable: InjectableDecorator = makeDecorator(
'Injectable',
undefined,
undefined,
undefined,
(type: Type<any>, meta: Injectable) => R3_COMPILE_INJECTABLE(type, meta)
);
Directive
export const Directive: DirectiveDecorator = makeDecorator(
'Directive',
(dir: Directive = {}) => dir,
undefined, undefined,
(type: Type<any>,
meta: Directive
) => R3_COMPILE_DIRECTIVE(type, meta));
Component
export const Component: ComponentDecorator = makeDecorator(
'Component',
(c: Component = {}) => ({changeDetection:ChangeDetectionStrategy.Default, ...c}),
Directive,
undefined,
(type: Type<any>, meta: Component) => R3_COMPILE_COMPONENT(type, meta)
);
Pipe
export const Pipe: PipeDecorator = makeDecorator(
'Pipe',
(p: Pipe) => ({pure: true, ...p}),
undefined,
undefined,
(type: Type<any>, meta: Pipe) => R3_COMPILE_PIPE(type, meta)
);
NgModule
export const NgModule: NgModuleDecorator = makeDecorator(
'NgModule',
(ngModule: NgModule) => ngModule,
undefined,
undefined,
(type: Type<any>, meta: NgModule) => R3_COMPILE_NGMODULE(type, meta)
);
参数说明
- 第一个参数: name, 装饰器的名字
- 第二个参数: props, 补充函数,可用于默认值设置
- 第三个参数:parentClass,父级对象
- 第四个参数:回调,参数是装饰器宿主对象
- 第五个参数:回调,参数是装饰器宿主对象和装饰器参数
执行结果
- 将装饰器处理的结果保存在宿主对象的__annotations__属相上,以供compiler编译器识别!
export const ANNOTATIONS = '__annotations__';
export function makeDecorator<T>(
name: string,
props?: (...args: any[]) => any,
parentClass?: any,
additionalProcessing?: (type: Type<T>) => void,
typeFn?: (type: Type<T>, ...args: any[]) => void
): {
new(...args: any[]): any;
(...args: any[]): any;
(...args: any[]): (cls: any) => any;
} {
const metaCtor = makeMetadataCtor(props);
function DecoratorFactory(...args: any[]): (cls: Type<T>) => any {
if (this instanceof DecoratorFactory) {
metaCtor.call(this, ...args);
return this;
}
const annotationInstance = new (DecoratorFactory as any)(...args);
return function TypeDecorator(cls: Type<T>) {
// 触发typeFn回调
if (typeFn) typeFn(cls, ...args);
const annotations = cls.hasOwnProperty(ANNOTATIONS) ?
(cls as any)[ANNOTATIONS] :
Object.defineProperty(cls, ANNOTATIONS, { value: [] })[ANNOTATIONS];
annotations.push(annotationInstance);
// 触发additionalProcessing回调
if (additionalProcessing) additionalProcessing(cls);
return cls;
};
}
if (parentClass) {
DecoratorFactory.prototype = Object.create(parentClass.prototype);
}
DecoratorFactory.prototype.ngMetadataName = name;
(DecoratorFactory as any).annotationCls = DecoratorFactory;
return DecoratorFactory as any;
}
function makeMetadataCtor(props?: (...args: any[]) => any): any {
// 返回一个函数
return function ctor(...args: any[]) {
if (props) {
const values = props(...args);
for (const propName in values) {
this[propName] = values[propName];
}
}
};
}
不过遗憾的是,angular并不支持自定义装饰器。
const testDecorator = makeDecorator('testDecorator');
@testDecorator()
export class TestDecorator { }
运行ng build通过ng serve通过,运行ng build --prod时报错
ERROR in main.ts(7,23): Error during template compile of 'TestDecorator'
Function calls are not supported in decorators but 'ɵmakeDecorator' was called.
报错位置
- @angular/compiler-static_reflector.ts>formatMetadataError
- @angular/compiler-static_reflector.ts>expandedMessage
case FUNCTION_CALL_NOT_SUPPORTED:
if (context && context.name) {
return `Function calls are not supported in decorators but '${context.name}' was called`;
}
return 'Function calls are not supported in decorators';
触发错误位置
- @angular/compiler-static_reflector.ts> simplify
因为conversionMap中没有注册
case 'call':
// Determine if the function is a built-in conversion
staticSymbol = simplifyInContext(
context, expression['expression'], depth + 1, /* references */ 0);
if (staticSymbol instanceof StaticSymbol) {
if (staticSymbol === self.injectionToken || staticSymbol === self.opaqueToken) {
return context;
}
const argExpressions: any[] = expression['arguments'] || [];
// 因为conversionMap中没有注册
let converter = self.conversionMap.get(staticSymbol);
if (converter) {
const args = argExpressions.map(arg => simplifyNested(context, arg))
.map(arg => shouldIgnore(arg) ? undefined : arg);
return converter(context, args);
} else {
// Determine if the function is one we can simplify.
const targetFunction = resolveReferenceValue(staticSymbol);
return simplifyCall(
staticSymbol,
targetFunction,
argExpressions,
expression['expression']
);
}
}
return IGNORE;
那看一下那里面都有什么吧!
private initializeConversionMap(): void {
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'Injectable'), createInjectable);
this.injectionToken = this.findDeclaration(ANGULAR_CORE, 'InjectionToken');
this.opaqueToken = this.findDeclaration(ANGULAR_CORE, 'OpaqueToken');
this.ROUTES = this.tryFindDeclaration(ANGULAR_ROUTER, 'ROUTES');
this.ANALYZE_FOR_ENTRY_COMPONENTS =
this.findDeclaration(ANGULAR_CORE, 'ANALYZE_FOR_ENTRY_COMPONENTS');
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'Inject'), createInject);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'Attribute'), createAttribute);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'ContentChild'), createContentChild);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'ContentChildren'), createContentChildren);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'ViewChild'), createViewChild);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'ViewChildren'), createViewChildren);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Input'), createInput);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'Output'), createOutput);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Pipe'), createPipe);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'HostBinding'), createHostBinding);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'HostListener'), createHostListener);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'Directive'), createDirective);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'Component'), createComponent);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'NgModule'), createNgModule);
// Note: Some metadata classes can be used directly with Provider.deps.
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Host'), createHost);
this._registerDecoratorOrConstructor(this.findDeclaration(ANGULAR_CORE, 'Self'), createSelf);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'SkipSelf'), createSkipSelf);
this._registerDecoratorOrConstructor(
this.findDeclaration(ANGULAR_CORE, 'Optional'), createOptional);
}
果不其然仅支持自家的装饰器
Injectable,InjectionToken,OpaqueToken,ROUTES,ANALYZE_FOR_ENTRY_COMPONENTS,Host,Self,SkipSelf,Inject,Optional,Attribute,ContentChild,ContentChildren,ViewChild,ViewChildren,Input,Output,Pipe,HostBinding,HostListener,Directive,Component,NgModule,Host,Self,SkipSelf,Optional
```ts
function makeMetadataFactory<T>(name: string, props?: (...args: any[]) => T): MetadataFactory<T> {
const factory: any = (...args: any[]) => {
const values = props ? props(...args) : {};
return {
ngMetadataName: name,
...values,
};
};
factory.isTypeOf = (obj: any) => obj && obj.ngMetadataName === name;
factory.ngMetadataName = name;
return factory;
}
创建处理器
const handlerTestDecorator = makeMetadataFactory('testDecorator',()=>{
//由于我们知识测试没啥实际功能
return {};
});
如果能注册到map里面我们就能通过编译,最后一步了,卧槽掉井里了,在compiler-cli里调用的。到此结束了!