You are unable to assign to the variable because it is declared as a readonly property in TypeScript

Take a look at this class:

export class Foo {
  id: string;

  static readonly questionKeyPrefix: string;

  constructor(id: string, _key: string) {
    this.id = id;

    if (!Foo.questionKeyPrefix) {
      // Error: Cannot assign to 'questionKeyPrefix' because it is a read-only property
      Foo.questionKeyPrefix = _key;
    }
  }
}

Whenever I attempt to modify the questionKeyPrefix, which is a static readonly property, it throws an error. I have also added a condition to ensure that it can only be set once!

If the static keyword is removed, everything works perfectly!

Any suggestions on how to resolve this issue?

Playground

Answer №1

Currently, the structure of your code is not functioning properly due to a static property that can change each time the constructor is called. This type of property cannot be marked as readonly since its value may change after initialization.

Based on the comments, it appears that this approach does not accurately reflect what you intend to achieve. You actually want the property to have different values for each subclass, rather than for each instance.


To solve this issue, consider making the property an instance property and assigning the appropriate value based on the subclass. You can pass this value from the subclass's constructor:

class Base {
    // instance field
    readonly key: string;
    constructor(_key: string) {
        this.key = _key;
    }
}

class Foo extends Base {
    constructor() {
        super('Foo');
    }
}

class Bar extends Base {
    constructor() {
        super('Bar');
    }
}

Playground Link

If you are concerned about exposing this property when serializing the object, you could make it a "virtual" property using get:

abstract class Base {
    abstract readonly key: string;
}

class Foo extends Base {
    get key() {
        return 'Foo';
    }
}

class Bar extends Base {
    get key() {
        return 'Bar';
    }
}

Playground Link

By declaring the getter per subclass, the value remains specific to each subclass instead of each instance.


In general, having a "static per subclass" concept is not very practical because static properties are not typically accessed polymorphically. This approach would only be viable if the classes themselves were treated as values, such as:

interface KeyedClass {
    readonly key: string;
}

class Foo {
    static readonly key = 'Foo';
}

class Bar {
    static readonly key = 'Bar';
}

function logKey(cls: KeyedClass) {
    console.log(cls.key);
}

logKey(Foo);
logKey(Bar);

Playground Link

Unless you specifically require this functionality, there is no benefit in establishing something as "static per class" since it cannot be accessed polymorphically from an instance context. Using this.key or Base.key in this scenario wouldn't provide the desired outcome; you would simply retrieve the base class's static property without adapting to the subclass context where this belongs to.

Answer №2

Static members in TypeScript can be initialized using static blocks.

abstract class Foo {
    id: string;

    static questionKeyPrefix: string = "";

    constructor(id: string, _key: string) {
      this.id = id;    
    }
}

class Bar extends Foo {
    static {
      Foo.questionKeyPrefix += "abc";
    }
}

console.log(Foo.questionKeyPrefix);

There is an issue with assigning readonly statics in static blocks which you can read more about here #56584.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The data event is not emitted by the socket in the http.ClientRequest

Trying to implement Time To First Byte (TTFB) using the http module in Node.js. I believe that the only way to achieve this is by adding a listener to a socket data event, but it doesn't seem to be working as expected. Below is an example of the code ...

What is the best way to show customized text from a data member within the :items object array for the item title in a v-select (Vuetify) dropdown menu

Currently, I am new to Vue and exploring Vuetify while working on building a dropdown using "v-select". If there is a simpler way to achieve this, it would be awesome! Otherwise, my plan is to create a new array, convert data for certain members into obje ...

Purging information from JavaScript object

Looking for a way to remove just one piece of data from a JavaScript object in my React app. Here's the structure of the object: state = { data: [] } const contactData = { Datas: { name: "william", email: "<a href="/cdn-cgi/l/email-pr ...

Retrieve indexedDb quota storage data

I attempted the code below to retrieve indexedDb quota storage information navigator.webkitTemporaryStorage.queryUsageAndQuota ( function(usedBytes, grantedBytes) { console.log('we are using ', usedBytes, ' of ', grantedBytes, & ...

Struggling to correctly assign a variable based on the input from a form

I am currently facing an issue where I am unable to retrieve input (specifically a number/float) from a text form and assign it to a variable for calculations. The assignment should occur when the calculate button is clicked. My attempt to use getElementB ...

Avoiding the sudden appearance of unstyled content in Single-File Components

I am looking to update my HTML navigation <div id="header-wrapper"> <div id="header-logo-title"> <nav> <ul id='mainNav'> <li>Home</li> </ul> </nav> ...

I am looking for a unique array that is distinct and can be used in a reusable function

I'm struggling to create a unique array using this function. ---Here is the Function I'm Working With--- var Array = [2, 0, 1, 9, 1, 3, 2, 4, 5, 5, 3, 4] function uniqueArrayValues(val){ var newArray=[]; for(var i=0 ; i < val.length ...

The static variable within the class remains unassigned when the callback function is invoked during app.listen

As I make the transition from JavaScript to TypeScript for developing my node.js applications, I find myself facing some confusion. For instance, I currently have this code snippet that initializes an express server: import * as express from 'expres ...

The art of blending different inheritance (Styled Elements)

Can components be based on other styled components? Take a look at the code snippets below. I am interested in creating a component like this: const HeaderDropDownLi = styled(DropDownLi, HeaderItem) Both DropDownLi and HeaderItem are derived from a style ...

Unable to recreate the Jquery Mobile Autocomplete demonstration

Attempting to recreate a demo using my own remote data source: The HTML page mirrors the demo, with one change: url: "http://localhost/sample.php", Here is the dummy remote data source sample.php <?php $a = array('apple', 'mango&apo ...

Issues with the rendering of vue-virtual-scroller are preventing proper display

I've been experimenting with https://github.com/Akryum/vue-virtual-scroller but I'm facing issues getting it to function properly. Can anyone point out what I might be doing incorrectly? My server-side rendering uses pug / jade and despite not e ...

Find the nearest class using JavaScript

How can I display reply forms in the comment section based on the specific comment reply button that has been clicked? Currently, it shows forms for all comments instead of just one. This is the question. What steps should I take to target the closest for ...

Interacting with Geoserver through ExtJs using an Ajax request

I am currently facing an issue with my ExtJS app where I am trying to send a request to a geoserver server. Although the URL displays correctly when accessed via the browser, I encounter an error when making the request within my app. The error message in ...

Is there a way to adjust the dimensions of Google charts within a Bootstrap tab for a more customized appearance?

I've been working on a page that features tab navigation using Twitter Bootstrap and I want to include Google charts within each tab's content. However, I've encountered an issue where the charts are appearing in different sizes despite spec ...

Transforming the text color after clicking on it on Squarespace - here's how to do it!

How can I make text change color upon clicking in Squarespace? Where should I place the block id in the code to target a specific block? Check out the code snippet I've been experimenting with: <script> document.getElementById('chang ...

Finding MongoDB data using an Express route and displaying it in a Jade template

Is there a way to retrieve data from MongoDB using an express route and display it in a jade template? Below is the code snippet of my express route (express version 2.5.8): app.get('/showData',function(req,res){ db.collection('comme ...

Retrieving data from multiple arrays using JavaScript

I have an array of hex colors. $.each(["#FF0000", "#000", "#FF6600", "#00E641"], function(i, c) { $('<input class="btns" type="button">') .css("background-color", color) .on("touch", $.proxy(funcNew, null, color)) .appendTo(" ...

Issue with Vuex reactivity when dealing with a list nestled inside an object

I attempted to build a scheduler app using vuex. To set up the scheduling, I utilized a state property named "scheduleController" which is structured as an object shown below. const state = { scheduleController: { 2020: { 11: { ...

Prevent elements from being altered using Angular or JavaScript

I need to prevent my element from being edited via any source, including Angular or JavaScript. This is what I've tried: <td> <script type="text/javascript"> $("#suppliername").each(function () { $(this).attr("readonly", "1"); ...

Display Page Separation with JavaScript

I am working on a project where I have created payslips using Bootstrap through PHP. To maintain organization, I am looking to create a new page after every 6 payslips. Below is the code snippet that I am using to generate the payslips: foreach($results a ...