Obtain the name of the property that is being accessed in TypeScript

I am looking to streamline my code by creating a set of generic methods to replace backing fields for properties. Specifically, I need to perform some common tasks in the setter (such as calling event emitters in Angular 5) and I want to avoid repeating this code every time.

So far, I have attempted three approaches:

  1. One option is to pass the property name as a string, but I would prefer to find an alternative to this method.

  2. I also experimented with using Error.stack, but found that parsing the stack trace varied among different browsers, which was not ideal.

  3. Upon trying to utilize arguments.callee.caller, I encountered the error:

    'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
    .

Do you have any other suggestions for achieving this?

Below is an example usage scenario. Pay attention to the

// somehow get calling property name
comment. Ideally, I would like a solution that returns the string "myProperty" in this particular case.

class ApplicationComponent {
    private readonly properties = new Map<string, any>();

    protected getProperty<T>(): T {
        const propertyName = // somehow get calling property name
        return <T>this.properties[propertyName];
    }

    protected setProperty<T>(value: T): void {
        const propertyName = // somehow get calling property name
        const oldValue = <T>this.properties[propertyName];

        if (oldValue === value) {
            return;
        }

        this.properties[propertyName] = value;

        const eventEmitter = this[`${propertyName}Change`];
        if (eventEmitter != null && eventEmitter instanceof EventEmitter) {
            eventEmitter.emit(value);
        }
    }
}

class SomeComponent extends ApplicationComponent {
    get myProperty(): SomeType {
        return this.getProperty();
    }

    set myProperty(value: SomeType) {
        this.setProperty(value);
    }

    readonly myPropertyChange = new EventEmitter<SomeType>();
}

Answer №1

Being verbose is crucial in scenarios where obtaining the property name reliably during production becomes a challenge. If getProperty and setProperty need to impact a specific property, they should be able to accept the property name as an argument.

This situation presents a perfect opportunity to leverage property decorators. By using a decorator that takes the class's prototype object and the property name, it becomes possible to define the property descriptor based on specific requirements:

function property(proto, key) {
  Object.defineProperty(proto, key, {
    get() {
      return this.properties[key]
    },
    set(val) { ... }
  });
}

class SomeComponent extends ApplicationComponent {
  @property
  myProperty: SomeType;
}

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

jQuery sidebar with a fixed position

Is there a way to implement a sidebar menu feature using jQuery that reappears on the left as the user scrolls down the page? You can see an example sidebar menu here. ...

Enhancing Hapi.js server functions with TypeScript: A guide

One way to enhance the functionality of the hapi module by adding type checking for server methods is shown in the following code snippet: import { Server } from 'hapi'; declare module 'hapi' { export interface Server { m ...

React - The ._id received by the Modal inside the map function is incorrect

My map is generating edit and delete buttons. The delete button requires confirmation, so I implemented a modal. When I use console.log(additive._id) on the first delete button, I get the correct ._id, but when I click the confirm button inside the modal, ...

Transform JSON data into HTML format while excluding particular values

I recently integrated a JSON API that fetches event data. Here's a snippet of the JSON structure: { "id":1, "status":"ok", "start":{ "date":"2021-01-16" } } To display this ...

What is the process of utilizing a pre-defined interface with the io-ts library?

Incorporating the @types/fabric package into my application has raised a query for me. I'm eager to utilize predefined interfaces such as ICircleOptions, IRectOptions, and others from fabric types. Is there a way to use these interfaces in conjunctio ...

Using the spread operator in combination with the reduce function in JavaScript

I am attempting to generate all possible paths of the provided JSON object. I have managed to generate the paths, but I would like the final array to be flattened without any nested arrays inside it. I tried spreading the array, but there are still some ne ...

Experimenting with an HTTP request in Angular 6 while testing a service method

I am facing an issue in one of my unit tests where a function containing an HTTP post request is not returning a string as expected. Below is the code snippet for the service function causing the problem: public getAnonToken(prev?: string): string { ...

Retrieving data from a subcollection in a cloud firestore database does not yield any results

In my Next.js application, I am utilizing Cloud Firestore database to store user documents. The structure of the collection path is as follows: collection "userDocs" └─ document "userEmail" └─ collection "docs" └─ document "document ...

What is the process for transpiling an individual node package while utilizing @babel/register within a Node.js environment?

When running a node server for SSR purposes, I encounter an issue with importing my (ES6+) React components. To resolve this, I utilize require('@babel/register') at the beginning of my file. However, some components rely on an ES6 package from n ...

Encountering a Next.js event type issue within an arrow function

After creating my handleChange() function to handle events from my input, I encountered an error that I'm unsure how to resolve. Shown below is a screenshot of the issue: https://i.sstatic.net/fWJA2.png I am currently working with Next.js. In React ...

What is the best way to navigate downwards within a specific div on a webpage using vertical scrolling?

I've scoured all the online forums, but I can't seem to find a solution to my problem. The web page I'm testing has a hidden link that I'm trying to locate manually through xpath or the element's ID attribute. However, when running ...

Struggling to retrieve information upon form initialization using JavaScript in Yii2

When the salary form loads, I need to retrieve data from the ratechart model and populate certain text fields. In the Ratechart Controller, I have included: public $rateid = '1'; public function actionGetForRatechart($rateid) { $ra ...

Is it possible to employ Java EE Servlets as the backend in conjunction with Angular serving as the frontend?

Is it feasible to integrate Angular (2+) as the frontend alongside Java EE Servlets as the backend? And is it possible to package the project as a WAR file? Your assistance is greatly appreciated. ...

What makes Reactive Extensions stand out as a game-changer?

What makes Reactive Extensions stand out as a game-changer for developers in both .NET and JavaScript? What are the key reasons for developers to dive into learning and implementing them? ...

Adding mCustomScrollbar to a dynamically created div using javascript steps

When making an ajax request, I retrieve data from the database and use JavaScript to generate HTML. However, there is an issue where the CatItemDetails div sometimes becomes too large and requires a scroll bar to display all the content. I attempted to ad ...

Every file downloaded through the iframe is automatically stored in a designated server folder

Is it possible for my website to have an iframe that enables users to browse the web, and when they click on a download button on any external website, the file can be saved directly to a specific folder on my server instead of their own computer? I'm ...

How can you maintain the "link" text in a div while removing the final hyperlink?

I am currently designing a breadcrumb navigation for a website. The breadcrumbs are generated using a templating language before the page is displayed. However, after rendering the page, I need to make some adjustments. Instead of using multiple IF/ELSE s ...

Issue with mat-selection-list search filter losing selections upon searching

Currently, I am working on incorporating a mat-selection-list that displays a list of characters. The unique feature is the ability to search and filter characters at the top of the list. Everything works smoothly except for one issue - when you select a c ...

What is the best way to distinguish between the paths for administrators and regular users?

Currently, I am in the process of setting up routes using node js for a dashboard. Firstly, users will need to log in to obtain a JWT token. With the Token, users can access various user-related routes such as editing, deleting, and logging out. However, ...

The method .depth() does not exist within this context

When I attempted to execute this code using npm start in the terminal //index.js const api = require('./api'); console.log('Starting monitoring!'); setInterval(async () => { //console.log(await api.time()); console.log(await ...