readonly properties and ngOnInit

Readonly properties can only be assigned in the constructor

Not true

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

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

As you see, there is already 3 ways of defining them. And probably more !

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

It is "discouraged" for newcomers, because it's easier to tell them not to do that, rather than explaining in depth the lifecycle of the framework. The point is, you can use the constructor as you please, especially for stuff unrelated to Angular (like read-only variables).

Is there any way to mark ngOnInit as a constructor

A constrcutor is a constructor. You can't define a method to be a constructor. You can only call a method in the constructor, but that won't solve your issue.

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

Answer and bottom line : use your constructor as you please. Put your readonly properties in it if you want.

Also, consider providing some sandbox or at least some code, so that we can make an answer that is adapted to both your code and your need.


You can't mark a method as a constructor there is just no syntax for that. You can break the readonly which is just a compile time check by using a type assertion to any and access any public/private property you want in a type unsafe way. You can also use a mapped type to make the type mutable, but it only works for public properties:

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

Why don't you use a setter and a getter in place of 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;
  }
}