只读属性和 ngOnInit

readonly properties and ngOnInit

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

编辑:澄清一下:我不是在寻找其他方法来声明只读属性。我想以常规方式声明它们。我认为任何其他不值得为了获得静态检查而牺牲可读性的东西。 我希望会有一些注释,比如 tslint 忽略 ngOnInit 中的不变性。

从目前的答案来看,我想将它们分配为 (this as any).foo = bar; 是最接近我想要做的,但我想它仍然比只留下只读更难看。

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

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 = ""
    }
}

为什么不用 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;
  }
}

这是个好问题。 您可以通过 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
    }
...

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

考虑到 Object.defineProperty 存在,更好的方法是按照@trichetriche

指出的那样使用它

Readonly properties can only be assigned in the constructor

不正确

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

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

如您所见,已经有 3 种定义方式。可能更多!

but in angular it is discouraged and sometimes impossible to use the constructor for certain initialization and instead the angular hook ngOnInit is used

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

Is there any way to mark ngOnInit as a constructor

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

so that I can use readonly for essentially immutable properties that are only assigned a single time in ngOnInit?

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

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