Is there a way to iterate through objects and update their values safely in typescript?

While utilizing Typescript, I encountered the issue described below.

My intention was to iterate through an object and modify its values.

Despite the functionality working smoothly, Typescript flagged it with an error.

How can I resolve this Typescript error in the given script?

const info = {
    id: "slkmd",
    password: "asdfasdf!",
    num: 1
}
const target = {
    id: "asdf",
    password: "asdf",
    num: 21
}
Object.keys(info).forEach(key => {
    info[key as keyof typeof info] = target[key as keyof typeof target]; // Error
    // Type 'string | number' is not assignable to type 'never'.
    // Type 'string' is not assignable to type 'never'
});

console.log(info);

Answer №1

In this scenario, the key type of the info object is either "id", "password", or "num". TypeScript recognizes these values, but it struggles to differentiate between them.

When you attempt the following:

info[key] = target[key]

It's akin to:

 info[key as "id" | "password" | "num"] = target[key as "id" | "password" | "num"]

Do you perceive the issue? TypeScript assumes that the first key could be password while the second key could be num, resulting in an incorrect assignment. TypeScript lacks the insight to grasp that key must be consistent within that union, only recognizing the type in each instance and flagging the appropriate type error.


To remedy this, the function should be made generic.

const keys = Object.keys(info) as Array<keyof typeof info>
keys.forEach<<K extends keyof typeof info>>(key: K) => {
    info[key] = target[key];
});

The inner function now incorporates a generic parameter K, representing a specific key of info, an individual member of that union.

The type of key within the function is:

K extends "id" | "password" | "num"

Indicating that it is a subtype of that union. Consequently, wherever type K is employed, it will be the same subtype of that union in that function call.

Therefore, the compiler's requirements are met.

Playground

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

When executing tests in jest, imports from node_modules may become undefined

My jest configuration seems to be encountering an issue with resolving node_modules during execution. They are coming back as undefined... Here is a snippet from my test file: import lodash from 'lodash' it('test', () => { expect ...

Angular2 displays an error stating that the function start.endsWith is not recognized as a valid function

After switching my base URL from / to window.document.location, I encountered the following error message: TypeError: start.endsWith is not a function Has anyone else experienced this issue with [email protected]? ...

When initializing a variable in Typescript, it is important to consider that the object may potentially be undefined

I've encountered a problem with a component in my app: @Component({ selector: 'app-payment-intent', templateUrl: './payment-intent.component.html', styleUrls: ['./payment-intent.component.css'] }) export class Payme ...

Tips for choosing a specific quantity and adjusting its value

Just starting out with Ionic 3 and looking for some help with the code. Can anyone assist me in understanding how to change the value of an item in a shopping cart and have the subtotal reflect that change? cart.ts private _values1 = [" 1 ", "2", " 3 "," ...

Encountering errors while adding Storybook to a TypeScript-react project with existing stories

I recently added storybook to my TypeScript React project, but I encountered an error when running yarn storybook. The issue seems to be related to the "as" keyword in the generated code. -- Error message Parsing error: Missing semicolon 10 | back ...

What could be the rationale behind the optional chaining operator not being fully compatible with a union of classes in TypeScript?

Imagine I have a combination of classes: type X = ClassA | ClassB | ClassC; Both ClassA and ClassC have a shared method called methodY. Why is it that I can't simply use the optional chaining operator to call for methodY? class ClassA { methodY ...

What is the best way to create a dynamic icon using React and TypeScript?

Excuse me, I am new to using React and TypeScript. I'm having trouble getting the icon to change based on the status in AppointmentType. The body color is working fine, but the icons are not changing. Can someone please help me solve this issue? const ...

Tips for successfully interacting with dynamic text areas using Protractor:

My current project involves e2e testing for an Angular 4 application with Protractor. Despite my efforts, I am struggling to locate a unique id, class, name or text identifier for a specific textarea within the application code. I need assistance in find ...

Change TypeScript React calculator button to a different type

I am currently troubleshooting my TypeScript conversion for this calculator application. I defined a type called ButtonProps, but I am uncertain about setting the handleClick or children to anything other than 'any'. Furthermore, ...

Send a collection of objects by submitting a form

I have a component with the following html code. I am attempting to dynamically generate a form based on the number of selected elements, which can range from 0 to N. <form #form="ngForm" id="formGroupExampleInput"> <div class="col-xs-5 col-md- ...

Error: Unable to locate namespace 'google' in TypeScript

I am currently working on an angular-cli project. ~root~/src/typings.json { "globalDevDependencies": { "angular-protractor": "registry:dt/angular-protractor#1.5.0+20160425143459", "jasmine": "registry:dt/jasmine#2.2.0+20160621224255", "sele ...

Changing the method signature in a TypeScript interface to replace/override the original one

For this specific scenario, the Array<T> interface is being extended in the following manner: interface BetterArray<T> extends Array<T> { push(this: BetterArray<T>, value: T): this; } Important note - the implementation of Arr ...

Utilizing an Angular Service within a method, embedded in a class, nested inside a module

module Helper { export class ListController { static handleBatchDelete(data) { // Implementing $http functionality within Angular ... $http.post(data) } } } // Trigger on button click Helper.ListController. ...

Transform a specialized function into a generic function with static typing

First off, I have a network of routes structured like this: interface RouteObject { id: string; path: string; children?: RouteObject[]; } const routeObjects: RouteObject[] = [ { id: 'root', path: '/', children: [ ...

Updating the data and processing results settings for Select2 in an Angular 2 application

In my Angular2 app, I am utilizing Select2 and facing a challenge with accessing class properties in the data and processResults contexts. Unfortunately, these contexts do not belong to the class: export class DefaultFormInputSelectComponent { @Input ...

Angular2 RC definitions are not recognized by tsc

Currently, I am utilizing angular version 2.0.0-rc.1, however, I am encountering issues with the typescript compiler (Typescript version 1.8.10). Whenever I run tsc on my project, I am bombarded with numerous errors similar to this one: app/app.componen ...

JSDoc encounters issues when processing *.js files that are produced from *.ts files

I am currently working on creating documentation for a straightforward typescript class: export class Address { /** * @param street { string } - excluding building number * @param city { string } - abbreviations like "LA" are acceptable ...

Tips for utilizing the 'crypto' module within Angular2?

After running the command for module installation: npm install --save crypto I attempted to import it into my component like this: import { createHmac } from "crypto"; However, I encountered the following error: ERROR in -------------- (4,28): Canno ...

Check if the input values are already in the array and if not, then add

Within my React application, I am displaying an Array and each entry in the Array is accompanied by an input element. These input elements are assigned a name based on the entry's ID, allowing users to enter values. To handle the changes in these inp ...

Guidelines for transmitting form information to a web API using Angular

I am currently working on an Angular 6 project where I have a form and a table that retrieves data from a web API. I want to know if it's possible to send the form data to that web API. Here is the code snippet that I have so far: HTML Form: &l ...