详解angular中的makeDecorator

首先说下作用:这个函数用来创建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里调用的。到此结束了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值