使用属性装饰器来初始化类

时间:2019-05-22 05:27:39

标签: angular typescript decorator

我试图在Angular 7中创建一个属性装饰器,以在set变量上初始化一个类

export class NewDataClass() {
   public readonly status = { loaded: false }
   public greet() {
      return 'hello';
   }
}

并构建一个装饰器,该装饰器返回带有某些参数的新类

export function NStatus() {
  return function(target: Object, key: string | symbol): any {

    return new NewDataClass();
  };
}

@Component({
  selector: 'app-new',
  templateUrl: './new.component.n.html',
  styleUrls: ['./new.component.n.scss']
})
export class NewComponent implements OnInit, OnDestroy {
  @NStatus() public status: NewDataClass;
}

初始化组件时,status的值应为new NewDataClass。帮助

1 个答案:

答案 0 :(得分:3)

您不能直接通过装饰器执行此操作。装饰器是在创建类(而不是实例化)时调用的,因此我们所要做的就是更改类本身以适应我们的需求。

一种选择是将字段转换为属性,并在getter上实例化值:

function NStatus() {
    return function (target: Object, key: string, desc?: PropertyDescriptor): PropertyDescriptor {
        return {
            get: function (this: Record<string, NewDataClass>) {
                return this["_" + key] || (this["_" + key] = new NewDataClass())
            },
            set: function (this: Record<string, NewDataClass>, value: NewDataClass) {
                this["_" + key] = value
            }
        }
    }
}

class NewComponent {
    @NStatus() public status: NewDataClass;
}

console.log(new NewComponent().status);

另一种选择,因为我们正在谈论角度分量,所以我们可以从装饰器覆盖ngOnInit并在那里进行初始化:

function NStatus() {
    return function <K extends PropertyKey>(target: { ngOnInit?: () => void  }, key: K): void {
        const originalNgOnInit = target.ngOnInit;
        target.ngOnInit = function (this: Record<K, NewDataClass>) {
            // Init the field
            this[key] = new NewDataClass;
            // Call original ngOnInit if any
            if(originalNgOnInit) originalNgOnInit.call(this);
        }
    }
}

class NewComponent {
    @NStatus() public status: NewDataClass;
    ngOnInit () {}
}

const c = new NewComponent()
c.ngOnInit();
console.log(c.status);

不幸的是,不可能从属性描述符中拦截类构造函数。