Skip to content

Allow assignment of uninitialized readonly base class properties in subclass constructor chain #25134

@ahamid

Description

@ahamid

This is an issue I run into often and forces me to choose between unnatural and convoluted initialization, redundant or weakened property declarations, or superfluous errors/warning noise I have to remember to ignore.

abstract class Base {
    readonly locomation: string // derived in subclass-specific way
}

class Bird extends Base {
    constructor() {
        super()
        this.locomation = 'fly' // cannot assign to constant or read-only property
    }
}

class Fish extends Base {
    constructor() {
        super()
        this.locomation = 'swim' // cannot assign to constant or read-only property
    }
}

It seems to make sense to me to relax the constraint to allow one-time initialization of a readonly property somewhere in the constructor chain. Subclass constructors are the most immediately statically analyzable locations, but the more general case might be private methods that are known only to be invoked during construction:

class ComplexInitialization {
  readonly derived: string
  constructor() {
    ...
    this.initialize()
    ...
  }
  private initialize() {
    this.derived = ...
  }
}

or even other initialization methods if they are known only to be invoked during construction:

// ComplexInitialization: broaden initialize visibility to `protected`
class DelegatedInitialization extends ComplexInitialization {
  protected initialize() {
    // still only called once during construction
    this.derived = ...
  }
}

Understood that the latter cases are harder to safely identify, but the simple case would go a long way. Absence of this ability essentially forces all values destined for readonly properties (and dependent context necessary to calculate them) to be hoisted up through the constructor call chain, or for readonly to be abandoned entirely.

I don't see this particular issue being reported (discussion on #8496 seems tangentially related, although in this issue I'm not suggesting the ability to ever re-assign a readonly property, and AFIAU I'm not asking to break existing readonly guarantees - I actually can't find readonly in the spec).

As far as I understand I think this suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript / JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. new expression-level syntax)

Metadata

Metadata

Assignees

No one assigned

    Labels

    DeclinedThe issue was declined as something which matches the TypeScript vision

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions