Automatically adding Typescript property decorator to the prototype

Looking to implement a feature in Java/TypeScript where I can automatically add properties without writing them into the constructor. As a beginner, my attempt might not be perfect. Here's what I have so far...

The idea is to achieve something like this:

class A {
  @uuid
  'property': string;
  'another': string;
}

function uuid(target: any, key: string): void {
  Reflect.defineMetadata('isUuid', true, target, key);
}

With A's constructor new () => Object, I should be able to retrieve all the properties and check if they are UUIDs like this:

Object.keys(A).forEach(key => {
  console.log(`[${key}].isUuid? ${Reflect.getMetadata('isUuid', A, key) === true}`);
});

This should ideally output:

[property].isUuid? true
[another].isUuid? false

If I modify class A as follows:

class A {
  constructor() {
    this.property = undefined;
    this.another = undefined;
  }
  @uuid
  'property': string;
  'another': string;
}

I can make it work, but I need to instantiate A to access the keys and metadata.

Answer №1

If you want to access all properties, each property needs to be decorated individually. Since the reflect-metadata API does not allow enumeration of targetKeys used on an object, it is recommended to store metadata directly on the object itself.

Begin by determining the type of information you wish to record for each property. For example, you can start with isUuid:

interface DbPropInfo {
  isUuid: boolean; 
  // other details
}

Setting default values for each piece of information helps in creating concise decorator annotations:

const defaultDbPropInfo: DbPropInfo = {
  isUuid: false 
}

The metadata should be stored in an object where keys correspond to the property keys of the class and values represent the DbPropInfo set for those properties. Here's a type definition for that object:

interface DbProps {
  [k: string]: DbPropInfo;
}

Now let's create the decorator:

const dbPropsKey = 'dbProps';

function dbProp(info?: Partial<DbPropInfo>) {
  return function(target: any, key: string): void {
    if (!Reflect.hasMetadata(dbPropsKey, target)) {
      Reflect.defineMetadata(dbPropsKey, {}, target);
    }
    const dbProps: DbProps = Reflect.getMetadata(dbPropsKey, target);
    dbProps[key] = Object.assign({}, defaultDbPropInfo, info);
  }
}

To retrieve the decorated data:

function getDbProps(ctor: { prototype: any }): DbProps | undefined {
  return Reflect.getMetadata(dbPropsKey, ctor.prototype);
}

Let's apply this concept to your class:

class A {
  @dbProp({ isUuid: true }) property: string;
  @dbProp() another: string;
}

Check if it works as expected:

console.log(JSON.stringify(getDbProps(A)));
// { 
//   "property": {"isUuid": true},
//   "another": {"isUuid": false}
// }

Does this solution meet your requirements?

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

define a function with default arguments and a callback

When working with a JavaScript library, I encountered an issue where I needed to define my callback functions within an object. The goal was to include default parameters in the arguments of these callback functions stored in a TypeScript object. Here is a ...

What is the best way to call a method from app.component in another component?

Having recently delved into Typescript and Angular 2, I've been struggling to find a solution online that fits my needs. Let's consider the example of an app.component: export class AppComponent implements OnInit { constructor(public _test ...

How to enable Access-Control-Allow-Origin for Angular 5 on the client side

I am currently utilizing the httpClient Angular package to make GET requests. The URL I am using to fetch data is , but I am encountering a CORS error in the console. Unfortunately, I do not have access to the server side code, but I still want to enable ...

Embed the div within images of varying widths

I need help positioning a div in the bottom right corner of all images, regardless of their width. The issue I am facing is that when an image takes up 100% width, the div ends up in the center. How can I ensure the div stays in the lower right corner eve ...

Ensuring correct association of values to avoid redundancies

There are 5 fields available for users to fill out on this form: Leave Code, From Date, Input Time1, To Date, and Input Time2. These variables are declared as a dates object in the .ts file, as shown below. interface Supervisor { name: string; code: s ...

Ensuring uniqueness in an array using Typescript: allowing only one instance of a value

Is there a simple method to restrict an array to only contain one true value? For instance, if I have the following types: array: { value: boolean; label: string; }[]; I want to make sure that within this array, only one value can be set to t ...

What steps are needed to develop a TypeScript component within Angular framework?

I've been attempting to develop an Angular Component in TypeScript. I'm trying to utilize document.createElement to build a toolbar within my component, but it's not appearing. Below is my Component code: import {Directive, Component, boot ...

JavaScript heap exhausted while running Docker container

Typically, I start my application by running npm run dev. The package.json file contains a script like the one below: "scripts": { "dev": "nodemon server.ts", } Everything is working fine in this setup. I have cr ...

The art of connecting models in Angular 2

Hey there! I've got a setup that seems to be giving me some unexpected results. Whenever I make changes to either the Kelvin or Celsius field, I end up with strange outputs like multiplying by 1000 or other inexplicable numbers. I'm new to Angula ...

Ways to break down a collection of multiple arrays

Looking to transform an array that consists of multiple arrays into a format suitable for an external API. For example: [ [44.5,43.2,45.1] , [42, 41.2, 48.1] ] transforming into [ [44.5,42], [43.2,41.2] , [45.1, 48.1] ] My current code attempts this ...

I'm attempting to conduct unit testing in my code using jest, but I keep encountering an error

I am currently testing unit testing in my code wherein a function takes two parameters and the goal is to check if the function is functioning properly. As a beginner in using jest, I am still learning how to write effective test cases. import React, { F ...

Drizzle-ORM provides the count of items in a findMany query result

Hello there, I'm currently experimenting with the Drizzle ORM and imagine I have this specific query const members = await trx.query.memberTable.findMany({ with: { comments:true } }) I'm wondering how I can retrieve the total count of me ...

Modifying the value upon saving in Adonis JS model

Using Adonis js I am facing an issue when trying to convert an ISO string to Datetime while saving data (the opposite of serializing DateTime fields to ISO string). I cannot find a way to do this in the model, like I would with a mutator in Laravel. Whene ...

Running the `npm start` command in Angular tends to be quite time-consuming

When I use Visual Studio Code to run Angular projects, my laptop seems to take a longer time when running the server through npm start compared to others. Could this delay be related to my PC specifications, or is there something I can do to improve it? ...

Fulfill the promise within yourself as well

I am looking to create a custom promise and have attempted the code below. My challenge lies in retrieving the value of recommendationCacheUrls after the inner promise, specifically the fileTransfer.download promise, has resolved. setNewCacheUrls(provided ...

How can I arrange a table in Angular by the value of a specific cell?

Here's the current layout of my table: Status Draft Pending Complete I'm looking for a way to sort these rows based on their values. The code snippet I've been using only allows sorting by clicking on the status header: onCh ...

Eliminate the chosen and marked items from a list - Angular 2+/ Ionic 2

Currently, I have a checkbox list on my page. Whenever a user selects the "Save" button, the checked items should be removed from the list and moved to the saved tab that is also displayed. While I have successfully implemented the functionality for removi ...

What is the best way to implement Angular 8's version of jQuery's ajax functionality?

I am in the process of transitioning from basic HTML and JavaScript to Angular for my web application. This means I need to rewrite my JavaScript Ajax calls to my PHP server controller in Angular syntax. As a beginner in writing Ajax calls with jQuery and ...

When trying to reload Angular 8 pages, encountering an error that reads "Cannot GET /login" and also receiving a notification stating the image '/favicon.ico' cannot be loaded due to a violation of

Encountering an issue with the error message "Cannot GET login/" appearing on the page body of my latest Angular 8 app. Despite attempting various solutions found on forums, I have been unable to resolve this error. Any suggestions or advice would be great ...

Typescript: Ways to fix the error 'rxjs/Rx does not have any exported member 'SubscriptionLike'

I'm attempting to replicate the steps outlined in this tutorial found here https://www.youtube.com/watch?v=gxCu5TEmxXE. However, upon running tsc -p, I encounter an error. Is there a specific import that I am missing? ERROR: node_modules/@angular/co ...