What is the process for modifying object information using string input in typescript?

How can I update an object's value in TypeScript based on a string input related to the object key?

const objData = { // random value
  A: 11,
  B: 13,
  C: 53,
  innerObj: {
    AStatus: true,
    BStatus: false,
    CStatus: true,
  },
};

type Item = 'itemA' | 'itemB' | 'itemC';

function processObj(item: Item, obj: typeof objData) {
  if (item === 'itemA') { // <- duplicate
    obj.A = 5;
    obj.innerObj.AStatus = true;
    return obj;
  }

  if (item === 'itemB') { // <- duplicate
    obj.B = 5;
    obj.innerObj.BStatus = true;
    return obj;
  }

  if (item === 'itemC') { // <- duplicate
    obj.C = 5;
    obj.innerObj.CStatus = true;
    return obj;
  }
  return
}

processObj('itemA', objData);

For example, when the input is itemA, only the data related to A in objData will be updated.

Typescript playground

Answer №1

When the connection between the item parameter and the key names within obj and obj.innerObj is determined programmatically through string manipulation, where a property key k of obj corresponds to a property k+"Status" of obj.innerObj and to the value "item"+k of item, you can optimize your processObj function using template literal types. Template literal types enable you to depict certain string manipulations at the type level. Here's a way to do it:

type Keys = Exclude<keyof typeof objData, "innerObj">;
// type Keys = "A" | "B" | "C"

function processObj(item: `item${Keys}`, obj: typeof objData) {
  const k = item.substring(4) as Keys; // need to assert here 
  obj[k] = 5;
  obj.innerObj[`${k}Status`] = true;
  return obj;
}

The Keys type employs the Exclude<T, U> utility type to filter the keys of objData by eliminating "innerObj", leaving us with the union

"A" | "B" | "C"
.

Furthermore, we utilize template literal types to conduct string concatenation at the type level. The type of item is `item${Keys}`, resulting in

"itemA" | "itemB" | "itemC"
. We derive k from item by removing the initial "item" prefix, leading to a type of Keys, although the compiler cannot confirm that. Hence, we simply assert that k aligns with type Keys.

We assign obj[k] = 5 without any compilation warning because the compiler recognizes that obj contains a number property across all keys within Keys. Similarly, setting

obj.innerObj[`${k}Status`] = true
doesn't trigger a compiler warning either, as the compiler comprehends that a template literal string value has a template literal type, and that the type of `${k}Status` equates to `${Keys}Status`, which evaluates to
"AStatus" | "BStatus" | "CStatus"
. Also, the compiler acknowledges that obj.innerObj features a boolean property at those specific keys.

Therefore, this process functions according to expectations.


Conversely, if the correlation between item and the keys present in obj and obj.innerObj is arbitrary, then utilizing string manipulation for mapping purposes might not be feasible. In such instances, employing a lookup table to embody the mapping structure would be more suitable. An implementation may resemble the following:

const propLookup = {
  itemA: "A",
  itemB: "B",
  itemC: "C"
} as const;
const statusLookup = {
  itemA: "AStatus",
  itemB: "BStatus",
  itemC: "CStatus"
} as const;
type Keys = keyof typeof propLookup;
// type Keys = "A" | "B" | "C"

function processObj(item: Keys, obj: typeof objData) {
  obj[propLookup[item]] = 5;
  obj.innerObj[statusLookup[item]] = true;
  return obj;
}

The propLookup and statusLookup objects represent mappings from valid item values to respective properties within obj and obj.innerObj. By incorporating const assertions, the compiler retains awareness of the string literal types associated with these values. Without as const, the compiler would deduce just string instead of providing meaningful insights.

This method also operates as intended; the compiler interprets propLookup[item] as a key of

obj</code containing a <code>number
value, while recognizing that statusLookup[item] pertains to a key within
obj.innerObj</code featuring a <code>boolean
value.

Playground link to code

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

Encountering a 405 error when making an OpenAI API call with next.js, typescript, and tailwind CSS

I encountered a 405 error indicating that the method request is not allowed. I am attempting to trigger an API route call upon clicking a button, which then connects to the OpenAI API. Unsure of my mistake here, any guidance would be highly appreciated. E ...

Leverage the power of npm to utilize various javascript libraries for

I seem to be a bit confused here. Currently, I have the following code snippets: import * as angular from 'angular'; import 'ts-angular-jsonapi'; Interestingly, no errors are being returned with this setup. But as soon as I try this: ...

What are the steps to resolve warnings in an imported json file?

I am working on a Vue project where I have imported a JSON file into my TypeScript script using import jsonData from '@/assets/data1.json'; Although the data is accessible and functions correctly, I am encountering numerous warnings during the b ...

Can you use TypeScript to define generic React functional components?

I am looking to add annotations to a generic in a React functional component like the following: import React, {useEffect, useState} from "react"; interface PaginatedTableProps{ dataFetcher: (pageNumber: number) => Promise<any>, columnNames: ...

The latest release of Angular2, rc1, eliminates all parameters that are not in

In the previous beta version, I was able to analyze using split Location.path(), but now it seems to have been removed. How can I prevent this removal? Interestingly, everything works well with matrix parameters (;id=123;token=asd). This was tested on a ...

Can a unique intrinsic type be created from scratch?

Ever since template literals were introduced in Typescript (PR), we've had access to various useful functions in our types: Uppercase Lowercase Capitalize Uncapitalize For more information, refer to the official documentation. Although it may seem ...

Connect the keys from one enum to either keys or values in another enum

When working with the code below, it is important that the keys of PropertiesNamesInDataBase align with those in User.Keys. While the values of PropertiesNamesInDataBase are used in the backend, it is crucial for uniformity that the names match in the fron ...

Struggling to retrieve posted data using Angular with asp.net

I have encountered an issue while sending a post request from Angular to my ASP.NET server. I am trying to access the values of my custom model class (SchoolModel) and I can see that all the values are correct inside Angular. However, when I attempt to ret ...

What is the process for transforming a Typescript source file into JavaScript?

I have a basic HTML file with a script source set to index.ts. index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge ...

How to check Internet upload speed in Angular without using a backend server?

I need help uploading a file to a folder within my Angular app's directory while it is running on localhost. I have been unable to find a solution that doesn't involve using backend technologies. For instance, I simply want to upload an image fi ...

How should we correctly import jquery.inputmask?

Struggling to import jquery.inputmask using webpack and TypeScript? Head over to this discussion at Issue #1115 : Here's how I configured things with jqlite: To import in your app, use the following code: import InputMask from 'inputmask&apos ...

What sets apart calling an async function from within another async function? Are there any distinctions between the two methods?

Consider a scenario where I have a generic function designed to perform an upsert operation in a realmjs database: export const doAddLocalObject = async <T>( name: string, data: T ) => { // The client must provide the id if (!data._id) thr ...

Utilizing Firebase Cloud Functions to perform querying operations on a collection

Imagine having two main collections: one for users and another for stories. Whenever a user document is updated (specifically the values username or photoUrl), you want to mirror those changes on corresponding documents in the story collection. A sample u ...

Authenticating to Google APIs using Node.js within a lambda function: A step-by-step guide

I'm encountering an issue when trying to connect a Google sheet to an AWS Lambda function. While the code runs smoothly during local testing, upon deployment to the function, I receive an error message indicating that the credentials.json file cannot ...

Using NodeJS to perform asynchronous tasks with setImmediate while also incorporating private class

Today marks my first time experimenting with setImmediate. I've come to realize that it may not be able to run private class methods. Can someone shed some light on this? Why is that the case? Not Functioning Properly When trying to use a private cl ...

Exploring ways to retrieve a function-scoped variable from within an Angular subscribe function

Here's the scenario: I have a simple question regarding an Angular component. Inside this component, there is a function structured like this: somethingCollection: TypeSomething[] ... public deleteSomething(something: TypeSomething): void { // so ...

Steps to access email template through an Excel web add-in

Currently, I am developing a new addin that aims to extract data from Excel and insert it into a word document. The final step would be attaching this document to an email in Outlook. While I have managed to achieve this using Power Automate, I prefer to ...

Ways to mock a static method within an abstract class in TypeScript

Having a difficult time testing the function Client.read.pk(string).sk(string). This class was created to simplify working with dynamoDB's sdk, but I'm struggling to properly unit test this method. Any help or guidance would be greatly appreciate ...

Jasmine: utilizing unit test to spy on the invocation of a nested function

When running unit tests for an Angular app, I need to spy on a function called func1 to check if it is being called. However, within func1 there is a call to func2 and I also want to spy on that to see if it is being called. How should I structure my unit ...

Automatic browser refresh with the `bun dev` command

Currently experimenting with the latest bun platform (v0.1.6) in conjunction with Hono. Here are the steps I followed: bun create hono test-api cd test-api bun dev After running the server, the following message appears: $ bun dev [1.00ms] bun!! v0.1.6 ...