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

Executing a service prior to the loading of Angular 7 applications or components

Currently, I am in the process of developing an application using Angular 7. So far, everything is running smoothly as I have successfully managed API calls, JWT Token authentication with C#, and updating LocalStorage when needed during user login and logo ...

Learning to utilize the i18n library with React Vite

The developer console is showing the following message: i18next::translator: missingKey en translation suche suche Here is the file structure of my project: vite.config.ts i18n.js test/ src/ components/InputSearch.tsx routes/ public/ de/translation. ...

What is the best approach for managing and obtaining accurate JSON responses when working with PHP API and AngularJS 2 services?

Encountering a backend issue with MySQL, wherein one query is producing a specific dataset: {"candidat":[{"ID":1,"nom":"Danny","prenom":"Hariot","parti":"Quamba","departement":"Ukraine","commune":"Chapayeve"},{"ID":2,"nom":"Shari","prenom":"Adamkiewicz"," ...

Displaying images dynamically in React from a source that is not public

There are 3 image options being imported, determined by the value in the state which dictates which of the 3 to display. import csv from '../../images/csv.svg'; import jpg from '../../images/jpg.svg'; import png from '../../images/ ...

JavaScript cannot determine the length of an array of objects

I'm encountering an issue with an array of objects named tagTagfilter. When I log it in the browser, it doesn't immediately show the correct length value inside. tagTagFilter: TagFilter = { filterName: 'Tag', tags: [] ...

Tips on avoiding the conversion of the ✳ symbol into an emoji

My issue lies in my ✳ (Eight-Spoked Asterisk) symbol being converted to an emoji on iOS/android devices. Find more about the Eight-Spoked Asterisk Emoji here. Could someone guide me on how to prevent the normal symbol ✳ from being transformed into an ...

Is it necessary for me to develop an Angular library in order to release a basic TypeScript class that makes use of Angular components?

In one of my Angular projects, I have a Typescript class called APIResponse that I want to convert into an NPM package for use in other projects. This class is not specific to Angular like a Service or Component. After doing some research on creating non-A ...

Material-UI - TypeScript - Autocomplete utilizing getOptionLabel and renderOption for optimized selection functionality

I am attempting to showcase member and company using MUI Autocomplete. I have an array called suggestion that contains the options to display. [ { "__typename": "Member", "id": "ckwa91sfy0sd241b4l8rek ...

How can I make sure that my function returns a mutated object that is an instance of the same class in

export const FilterUndefined = <T extends object>(obj: T): T => { return Object.entries(obj).reduce((acc, [key, value]) => { return value ? { ...acc, [key]: value } : acc; }, {}) as T; }; During a database migration process, I encounte ...

Exploring the Power of SectionList in Typescript

How should SectionList be properly typed? I am encountering an issue where this code works (taken from the official documentation example): <SectionList renderItem={({item, index}) => <Text key={index}>{item}</Text>} renderSectionHea ...

How can you ensure in Typescript that a function parameter belongs to a specific set of enumerated values?

Consider this example enum: export enum MyEnum { a = "a", b = "b", c = "c" } Now, let's define a function type where the parameter must be one of these values. For instance, myFunction("c") is acceptabl ...

Using React's `cloneElement` to make modifications to a child component while maintaining the reference within a functional component

In the past, I had references in my component while rendering, and it was functioning as expected: // props.children is ReactElement<HTMLDivElement>[] const [childRefs] = useState<RefObject<any>[]>(props.children.map(() => createRef()) ...

Adding date restrictions to the main method is necessary for controlling the input and output

I have a function in my react-native package that requires "from" and "to" dates as parameters. I need to implement a rule that ensures the "to" date is always after the "from" date. Where should I insert this requirement in the following code snippe ...

Implement a nested filter in Angular 8 to enhance data manipulation

Is it possible to apply a filter inside another filter in this scenario? I have a table of orders with nested tables of services, and I want to only display the orders where the type of service is 'type1'. I tried using the following line of code ...

Is the translation pipe in Angular 5 impure?

I'm currently utilizing ngx-translate. Can you tell me if the translation pipe is considered pure or impure? Also, would it be more beneficial to use the directive syntax translate="X" instead? ...

Error message when using Typescript with Redux Saga: "Cannot use 'then' property on type 'void'. TS2339"

Whenever I attempt to fetch data from this API endpoint using promises, I encounter these type of issues. export function* signUpWithEmail(authInfo: any) { const { email, password } = authInfo.payload try { const response = yield authSignUpService ...

What is the reason for the truth value of `type a = {} extends {a?:number}? true:false;`?

Why is type a = {} extends {a?:number}? true:false; evaluated as true, while type b = {a?:number} extends {}? true:false; is also true! It seems like the empty object {} acts as a supertype that can extend other types. This raises some questions about ...

Effectively managing user access by authorizing levels and securing routes

Below is the code snippet for a protected route where the authentication status is managed by Redux. If there is no token saved in local storage, the isAuthenticated state is set to false. This code snippet is for protecting routes: import PropTypes from & ...

What is the reason behind the Partial input basic type returning itself?

Snippet of code excerpt: type PartialType<T> = { [P in keyof T]?: T[P]; } I am curious about why the PartialType input basic type (such as string returning string) returns itself instead of throwing an error or an object. // undef => undefined t ...

Error Encountered While Building AWS Amplify with Ionic 5 and Angular 10

Our team is currently facing a challenge at my company that we've been struggling to resolve, and I was hoping someone here could offer some assistance. We are using AWS Amplify in our Angular 10/Ionic 5 project, and encountering the following error: ...