retrieve a nested object's property using a dynamic string

Here is the object model I am working with:

export class FrcCapacity {
  constructor(
    public id?: number,
    public frcId?: number,
    public capGroupId?: number,
    public capGroup?: CapGroup,
    public salesProductId?: number,
    public p1?: number,
    public p2?: number,
    public p3?: number,
    public p4?: number,
    public p5?: number,
    public p6?: number,
    public p7?: number,
    public p8?: number,
    public p9?: number,
    public p10?: number,
    public p11?: number,
    public p12?: number,
    public total?: number
  ) {}
}

I have an array called frcCapacity, which is filled with objects based on the above model.

My goal is to write a function that will update the value of a specific field (px) in the processed object. Here's what the function body looks like:

periodValueChange(val: string, rowIndex: number, field: string) {
    for (let [key, value] of Object.entries(this.frcCapacity[rowIndex])) {
      if (key === field) this.frcCapacity[rowIndex]???
    }
  }

I attempted to use Object.entries but I'm unsure how to access the px field based on the field parameter. Can you provide guidance on this?

After some research and experimentation, I found a solution that works:

periodValueChange(val: string, rowIndex: number, field: string) {
    let frcCap = this.frcCapacity[rowIndex];
    let map = new Map(Object.entries(frcCap));
    for (let [key, value] of map) {
      if (key === field) {
        map.set(field, +val);
      }
    }
    let obj = Array.from(map).reduce(
      (obj, [key, value]) => Object.assign(obj, { [key]: value }),
      {}
    );
    this.frcCapacity[rowIndex] = obj;
  }

Essentially, I needed a solution like this:

periodValueChange(val: string, rowIndex: number, field: string) {
    this.frcCapacity[rowIndex].field = +val;
  }

Where the field parameter can be p1, p2, and so on.

Answer №1

It appears that the usage of string for both the property name (field) and the value (val) indicates a scenario where these strings are sourced from a location restricted to strings only, such as form fields. This situation presents two main challenges:

  1. The field string could potentially be an invalid property name within the context of FrcCapacity objects.

  2. The val string may not align with a valid value corresponding to the property identified by field.

To handle this in a predominantly type-safe manner, the solution involves incorporating a function that verifies whether a given key is a legitimate key for FrcCapacity, like an assertion function tailored for type validation:

function assertIsValidFrcCapacityKey(key: string): asserts key is keyof FrcCapacity {
    switch (key) {
        case "id":
        case "frcId":
        case "capGroupId":
        // ...and further validations pertinent to valid property names...
            break;
        default:
            throw new Error(`${key} is not a valid key for FrcCapacity objects`);
    }
}

This approach informs TypeScript that if no exceptions are caught during the execution of the function, the input key can indeed be considered a valid key applicable to FrcCapacity objects. While it may seem suboptimal to manually list out all property names, this methodology remains effective for enforcing proper type handling.

Furthermore, addressing the conversion between number and CapGroup necessitates a specific implementation within the function code itself:

periodValueChange(val: string, rowIndex: number, field: string) {
    assertIsValidFrcCapacityKey(field);
    if (field === "capGroup") {
        frcCapacity[rowIndex].capGroup = convertStringToCapGroup(val);
    } else {
        frcCapacity[rowIndex][field] = +val;
    }
}

(In the sample above, I've utilized unary + for converting the string val into a number. Alternative methods exist for achieving this conversion, each carrying their own merits and drawbacks, as outlined here. The actual implementation of convertStringToCapGroup has been omitted, pending clarification on what exactly constitutes a CapGroup and how its encoding as a string occurs within your form structure.)

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

How can I assign a type to an array object by utilizing both the 'Pick' and '&' keywords simultaneously in TypeScript?

As a beginner in TypeScript, I am looking to declare a type for an array object similar to the example below. const temp = [{ id: 0, // number follower_id: 0, // number followee_id: 0, // number created_at: '', // string delete_at: &ap ...

The "if(x in obj)" statement in Typescript does not properly narrow down my custom Record

I am struggling with a code snippet where I am trying to check if a string exists in my custom record using the if(x in obj) guard statement, but it seems to not be working as expected. Below is the sample code snippet that is throwing an error: type Ans ...

What is the best way to incorporate an external .css file into my Angular project by referencing its URL?

I'm managing a collection of CSS files online and I need to incorporate each one into my project based on its specific requirements. One component in particular is connected to different numerical IDs in the router. I am looking for a way to dynamica ...

Exploring the Usage of Jasmine Testing for Subscribing to Observable Service in Angular's OnInit

Currently, I am facing challenges testing a component that contains a subscription within the ngOnInit method. While everything runs smoothly in the actual application environment, testing fails because the subscription object is not accessible. I have att ...

ng-click-outside event triggers when clicking outside, including within child elements

I am looking to trigger a specific action when I click outside of the container. To achieve this, I have utilized the ng-click-outside directive which works well in most cases. However, there is one scenario where an issue arises. Inside the container, the ...

Error in NextJS: Attempting to access a length property of null

Does anyone have insights into the root cause of this error? warn - Fast Refresh had to perform a full reload. Read more: https://nextjs.org/docs/basic-features/fast-refresh#how-it-works TypeError: Cannot read properties of null (reading 'lengt ...

While using axios to make a GET request, I encountered errors when checking for .isSuccess in react

const searchInvoiceList = async ( plantLocation: string, invoiceType: string ) => { let dataList: InvoiceData[] = []; await axios .get(`${linkURL}inv/getControlList/${plantLocation}/${invoiceType}`) .then((response) => { dataLis ...

The index declaration file has not been uploaded to NPM

After creating a Typescript package and publishing it on NPM, I encountered an issue with the declaration files not being included in the published version. Despite setting declaration: true in the tsconfig.json, only the JavaScript files were being publis ...

Encountering errors while attempting to install TypeScript through NPM

I am encountering an issue while trying to install Typescript using npm. Following the documentation, I executed the command: npm install -g typescript or sudo npm install -g typescript - Everything seems to be going smoothly until it reaches about 2 ...

What is the best approach for resolving this asynchronous task sequencing issue in JavaScript?

Below is a code snippet where tasks are defined as an object and the function definition should ensure the expected output is met. Let tasks = { ‘a’: { job: function(finish){ setTimeout(() => { ...

Guide on importing absolute paths in a @nrwl/nx monorepo

I am currently working on a @nrwl/nx monorepo and I am looking to import folders within the project src using absolute paths. I attempted to specify the baseUrl but had no success. The only solution that did work was adding the path to the monorepo root ts ...

What is the best approach for defining variables in typescript?

Let's talk about creating a variable for a car: export class ICar { wheels: number; color: string; type: string; } So, which way is better to create the variable? Option one: const car = { wheels: 4, color: 'red', type: &apos ...

Encountering issues with integrating interactjs 1.7.2 into Angular 8 renderings

Currently facing challenges with importing interactive.js 1.7.2 in Angular 8. I attempted the following installation: npm install interactjs@next I tried various ways to import it, but none seemed to work: import * as interact from 'interactjs'; ...

Angular 5 - Jasmine Tests explained: Encounter with the puzzling error message: "Error: Provider for the NgModule 'DynamicTestModule' is invalid, as only instances of Provider and Type are permitted"

I'm having trouble running tests on a component class. Here's the error message from the stack: Error: Invalid provider for the NgModule 'DynamicTestModule' - only instances of Provider and Type are allowed, got: [AlertModaldataCompon ...

Sending binary information from a .net core web api to a typescript application

I currently have a .net core 3.0 web api application connected to an angular 8 client. While I have successfully transferred data between them using json serialization, I am now looking for a way to transfer a bytes array from the api to the client. After ...

Submitting the form leads to an empty dynamically added row

I am currently working on a gender overview that allows you to edit, add, or delete genders using a simple table. The functionality of adding and deleting rows is already implemented. However, I am facing issues with displaying the correct web API data as ...

Compiler is unable to comprehend the conditional return type

I've done some searching, but unfortunately haven't been able to find a definitive solution to my issue. Apologies if this has already been asked before, I would appreciate any guidance you can offer. The problem I'm facing involves a store ...

Capture all HTTP requests made by Angular2

I'm trying to find a way to intercept and modify all HTTP requests made by Angular by adding custom headers. In previous releases prior to angular2 RC5, this was achieved by extending the BaseRequestOptions like this: class MyOptions extends BaseRequ ...

Converting hexadecimal to binary using Javascript or Typescript before writing a file on an Android or iOS device

Hey everyone! I'm facing a puzzling issue and I can't seem to figure out why it's happening. I need to download a file that is stored in hex format, so I have to first read it as hex, convert it to binary, and then write it onto an Android/ ...

Centralized MUI design for varying screen dimensions

I am struggling to perfectly center my modal box in the middle of the screen. The problem arises when the screen size changes, causing the box to be misaligned. I attempted using top:50% and left: 50%, but this did not effectively center the box. center ...