Tips for saving metadata about properties within a class

I am looking to add metadata to properties within classes, specifically using abbreviations for property names.

By using annotations like @shortName(abbreviated), you can label each property as follows:

function shortName(shortName: string){
    return function (target: Object, realName: string){
        // Where should I store the relationship between realName <-> shortName ??
    }
}
class Record{
    @shortName("ts") typeOfStorage: string;
}
class Client extends Record{
    @shortName("df") descriptiveField: string;
}
function mapNames(obj: any){  // Return object with shortened names
    let ret = {};
    for(let prop in obj){
        //Here retrieve the short name and add it to ret
    }
    return ret;
}

let client = new Client();               // assuming: { typeOfStorage: "f", descriptiveField: "blah"}
let clientShortened = mapNames(client);  // expected output:  {ts: "f", df: "blah"}

The challenge lies in determining where and how to store these relationships so they are accessible in instances of derived classes.

Initially, I attempted creating a global map prefixed with target.constructor.name (which provides the class name). However, in an inherited class, the constructor.name is that of the inherited class (resulting in losing track of typeOfStorage in the client example).

(This approach aims to optimize storage space when storing objects in non-SQL databases such as Firestore by storing each property name of each object record)

Answer №1

To effectively store and access a map in the prototype of a class, one can utilize a recursive process of retrieving the prototype chain using Object.getPrototypeOf. This approach involves merging all the maps present in the prototype chain or individually looking up properties in each map.

function assignShortName(shortName: string)
{
    return function (target: Object, realName: string)
    {
        const t = target as { _propMap?: Map<string, string> };

        if (t._propMap == null)
        {
            // Implementing enumerable: false to hide the property 
            Object.defineProperty(t, '_propMap', {
                enumerable: false,
                writable: true,
            });

            t._propMap = new Map<string, string>();
        }

        t._propMap.set(realName, shortName);
    }
}

function retrieveMap(obj: any)
{
    const map = new Map<string, string>();
    while (true)
    {
        obj = Object.getPrototypeOf(obj);
        if (obj == Object.prototype)
            return map;

        if (obj._propMap)
        {
            let subMap = obj._propMap as Map<string, string>;
            subMap.forEach((v, k) => map.set(k, v));
        }
    }
}

function nameMapper(obj: any)
{
    const map = retrieveMap(obj);

    const ret: any = {};
    for (let prop in obj)
    {
        const name = map.get(prop) ?? prop;
        ret[name] = obj[prop];
    }

    return ret;
}

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

Data fetched by Next.js is failing to display on the web page

After writing a fetch command, I was able to see the data in the console.log but for some reason it is not showing up in the DOM. export default async function links(){ const res = await fetch('https://randomuser.me/api/'); const data = ...

Tips for successfully passing function variables as parameters to Angular 2 HTTP subscribe callbacks

I attempted this.propositionService.addProposition(this.proposition) .subscribe(this.addSuccessCallback, this.addFailureCallback); The issue I am encountering is that both addSuccessCallback and addFailureCallback do not have acces ...

Typescript tutorial: Implementing a 'lambda function call' for external method

The Issue Just recently diving into Typescript, I discovered that lambda functions are utilized to adjust the value of this. However, I find myself stuck on how to pass my view model's this into a function that calls another method that hasn't b ...

Typescript typings for child model/collection structures

I have encountered an issue while trying to implement a Model/Collection pattern with various typings. Both the Model and Collection classes have a method called serialize(). When this method is called on the Collection, it serializes all the Model(s) with ...

What could be causing my Vue code to behave differently than anticipated?

There are a pair of components within the div. When both components are rendered together, clicking the button switches properly. However, when only one component is rendered, the switch behaves abnormally. Below is the code snippet: Base.vue <templa ...

Problems with installing ambient typings

I'm having trouble installing some ambient typings on my machine. After upgrading node, it seems like the typings are no longer being found in the dt location. Here is the error message I am encountering: ~/w/r/c/src (master ⚡☡) typings search mo ...

Tips for simulating difficult private attributes within a class during unit testing in TypeScript

Is there a way to mock the value of a hard private property in a unit test? For example, how can I expect something like expect(event.getEventHis()).toBeEqual(['a', 'b']) export class EventController { #event: []; constructor() { ...

When a parameter is passed into a React-Query function with an undefined value, it can lead to the API returning a 404 error

Two parameters are sent from the frontend to trigger a GET request in another TypeScript file. It seems that one of the parameters is not successfully passed due to unknown rerenders, resulting in a 404 Error being returned by the API call in the console. ...

Issue with conflicting namespaces warning when compiling an Angular 9 project with ng-packagr using Typescript

I'm trying to pinpoint the root cause of this problem, and I suspect it may be related to Typescript. However, it could also involve ng-packagr or Angular. This issue only arose after upgrading to Angular 9. Upon building my production environment, I ...

Instructions on how to implement a readmore button for texts that exceed a specific character length

I am attempting to display a "Read more" button if the length of a comment exceeds 80 characters. This is how I am checking it: <tr repeat.for="m of comments"> <td if.bind="showLess">${m.comment.length < 80 ? m.comment : ...

Utilizing TypeScript to perform typing operations on subsets of unions

A TypeScript library is being developed by me for algebraic data types (or other names they may go by), and I am facing challenges with the more complex typing aspects. The functionality of the algebraic data types is as follows: // Creating ADT instatiat ...

The issue arises when Jest fails to align with a custom error type while utilizing dynamic imports

In my project, I have defined a custom error in a file named 'errors.ts': export class CustomError extends Error { constructor(message?: string) { super(message); Object.setPrototypeOf(this, Error.prototype); this.nam ...

Discovering the power of Angular 2 with ngrx while putting my Reducer to the

Within my Reducer file: case PumpActionTypes.EnterLocalMode: return commandOne.upsertOne( {id: action.payload.id, changes: { local: false }}, state ); When testing, I aim to verify that the local property is indeed modified to false. My curr ...

Uniting 2 streams to create a single observable

I am in the process of merging 2 different Observables. The first Observable contains a ShoppingCart class, while the second one holds a list of ShoppingItems. My goal is to map the Observable with shopping cart items (Observable<ShoppingItems) to the i ...

I am puzzled by this error in Typescript: "Why does the element have an 'any' type when the Object type lacks an index signature?"

Looking to extract an array of keys from an object with nested properties, my current code: public static getKeys(obj: Object) { let keys: string[] = []; for (let k in obj) { if (typeof obj[k] == "Object" && obj[k] !== null) { ...

Exploring Function Overriding in TypeScript

Currently, I'm working on developing a TypeScript method. import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ p ...

Provider not found: ConnectionBackend – NullInjectorError

I encountered the following error while attempting to load the webpage. Despite trying various suggestions from other sources, I have been unable to find a solution. Below the error stack lies my code. core.js:7187 ERROR Error: Uncaught (in promise): Null ...

remove a specific element from an array

Hey there! I'm attempting to remove only the keys from an array. Here's the initial array: {everyone: "everyone", random: "random", fast response time: "fast response time", less conversations: "less conversatio ...

I am interested in utilizing Vue Fallthrough attributes, but I specifically want them to be applied only to the input elements within the component and not on the container itself

I am facing an issue with my checkbox component. I want to utilize Fallthrough attributes to pass non-declared attributes to the input inside the checkbox component. However, when I add HTML attributes to the Vue component, those attributes are applied not ...

Having difficulty installing TypeScript on my machine

https://i.stack.imgur.com/l6COf.pngHaving trouble installing TypeScript with the following error: npm WARN registry Using outdated package data from https://registry.npmjs.org/ due to an error during revalidation. npm ERR! code E500 npm ERR! 500 Interna ...