7

只读属性只能在构造函数中赋值,但在 Angular 中,不鼓励并且有时不可能使用构造函数进行某些初始化,而是使用 Angular 钩子 ngOnInit。有没有办法将 ngOnInit 标记为关于 readonly 属性的构造函数,以便我可以将 readonly 用于仅在 ngOnInit 中分配一次的本质上不可变的属性?

编辑:澄清:我不是在寻找替代方法来声明只读属性。我想以常规方式声明它们。我认为其他任何事情都不值得为了获得静态检查而牺牲可读性。我希望会有一些注释,就像 tslint 忽略 ngOnInit 内部的不变性一样。

从到目前为止的答案来看,我想将它们分配为(this as any).foo = bar;最接近我想做的事情,尽管我想它仍然比仅仅省略只读更难看。

4

4 回答 4

4

只读属性只能在构造函数中赋值

不对

class MyClass {
  readonly prop1 = 'prop1';
  constructor(
    public readonly prop2 = 'prop2'
  ) {
  }

  ngOnInit() {
    Object.defineProperty(this, 'prop3', { wirtable: false, value: 'prop3'});
  }
}

如您所见,已经有 3 种定义它们的方法。而且可能更多!

但是在 Angular 中,不鼓励并且有时不可能使用构造函数进行某些初始化,而是使用 Angular 钩子 ngOnInit

对于新手来说是“不鼓励”的,因为告诉他们不要这样做更容易,而不是深入解释框架的生命周期。关键是,您可以随意使用构造函数,尤其是对于与 Angular 无关的东西(如只读变量)。

有什么方法可以将 ngOnInit 标记为构造函数

构造函数是构造函数。您不能将方法定义为构造函数。您只能在构造函数中调用一个方法,但这不会解决您的问题。

这样我就可以将只读属性用于在 ngOnInit 中只分配一次的本质上不可变的属性?

答案和底线:随意使用您的构造函数。如果需要,将您的只读属性放入其中。

此外,请考虑提供一些沙箱或至少一些代码,以便我们可以做出适合您的代码和您的需求的答案。

于 2019-03-01T10:12:05.003 回答
2

您不能将方法标记为构造函数,只是没有语法。您可以通过使用类型断言来打破readonly这只是编译时检查,any并以类型不安全的方式访问您想要的任何公共/私有属性。您还可以使用映射类型来使类型可变,但它仅适用于公共属性:

type Mutable<T> = { -readonly [ P in keyof T]: T[P] }

class Foo {
    public readonly data: string;
    private readonly pdata: string;
    public init() {
        const ref: Mutable<this> = this;
        ref.data = "" 
        const pRef = this as any;
        pRef.pdata = ""

        const pSaferRef: { pdata: string } = this as any;
        pSaferRef.pdata = ""
    }
}
于 2019-03-01T09:53:32.127 回答
2

为什么不使用 setter 和 getter 来代替readonly

export class MyComponent {
  private _value: string;
  set value(v: string) {
    if (!this._value) {
      this._value = v;
    } else {
      throw new TypeError('Assignment to read-only variable');
    }
  }

  get value() {
    return this._value;
  }
}
于 2019-03-01T09:59:06.693 回答
0

这是个好问题。你可以通过 setter 得到类似的东西:

...
    protected _pseudoReadonlyProp: number = -1 // or some other value, that marks unititialized state
    set pseudoReadonlyProp(a: number) {
        if(this._pseudoReadonlyProp != -1) {
           // throw some error here
        }
        this._pseudoReadonlyProp = a
    }
    get pseudoReadonlyProp(): number {
        return this._pseudoReadonlyProp
    }
...

获得类似行为的另一种方法是将只读成员封装在一个类中,将其放入您的组件中,并在 ngInit 或其他一些组件初始化函数中创建该类的新实例。

考虑到 Object.defineProperty 存在,更好的方法是使用它,正如@trichetriche 所指出的那样

于 2019-03-01T10:00:09.727 回答