Employing TypeScript to utilize dynamic keys on objects

I am working with a function that looks like this

interface Cat {
    color: string,
    weight: number,
    cute: Boolean, // even though all cats are cute!
}

export const doSomething = (
    cat: Array<Cat| null>,
    index: number,
    key:  keyof typeof cat,
    payload: string | number | Boolean
) => {
    ....
    cat[key] = payload
    ....
}

As a result, I get the error message:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type

This occurs because TypeScript is interpreting key as any string instead of one of

"color", "weight", "cute"
. How can I specify in the function declaration that key should be one of these three values?

I attempted to use

...
key:  keyof Cat,
...

but it did not work. Now, when I try to assign the value using

 cat[key] = payload

I receive the following error:

Type 'string| number | Boolean | ' is not assignable to type '(string & number & Boolean )

Answer №1

cat is actually an array, so when you use keyof typeof cat, you're getting the keys of the array and not from the Cat interface. To access keys from the Cat interface, you should specifically use keyof Cat.

export const doSomething = (
    cat: Array<Cat | null>,
    index: number,
    key: keyof Cat,
    payload: string | number | Boolean
) => {
    cat.forEach(c => {
        if (c) {
            c[key] = payload
        }
    });
}

However, this function still doesn't work perfectly because there's no connection between the key and the payload. For instance, you could call doSomething(.., ..., 'cute', 1).

In order to link the payload with the key, you need to add a generic type parameter:

export const doSomething = <K extends keyof Cat>(
    cat: Array<Cat | null>,
    index: number,
    key: K,
    payload: Cat[K]
) => {
    let c = cat[index];
    if (c) {
        c[key] = payload
    }
}

Playground Link

The usage of K as a generic type parameter in the code above enables capturing additional information from the call site, turning it into a generic function. In this context, K extends keyof Cat specifies that K must be a subtype of keyof Cat, meaning it can only be one of "color", "weight", or "cute".

When you invoke

doSomething([], 0, "cute", true)
, K will represent "cute". Armed with this information about the called function, you can utilize it within a type query (Cat[K]) to acquire the actual type of the property linked to the key "cute".

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

Connecting data with Angular

Recently, as part of my learning journey with Angular, I encountered an intriguing issue. While working on my code, I noticed that the error popped up in my code editor (VSCode) but not when running the code in the browser. The dilemma stemmed from settin ...

The limitations of Typescript when using redux connect

Recently, I utilized TypeScript for React to declare a class with constraints and now I'm looking to implement the connect method. Here is the code snippet: import * as React from 'react'; import { connect } from 'react-redux'; im ...

What could be causing the node inspector to fail to launch when using nodemon and ts-node together?

I have a basic node server set up in typescript. The configuration in my package.json file looks like this: "scripts": { "build": "tsc", "dev": "nodemon --watch src/**/* -e ts,json --exec ts-node ./src/server.ts", "debug": "nodemon --verbose --wat ...

I'm struggling to find the right Typescript syntax for defining a thunk function that returns a value while using React Redux Toolkit

Currently, I am utilizing TypeScript within a React Redux Toolkit project. While attempting to create an Async Thunk action function that is expected to return a boolean value, I found myself struggling with determining the correct TypeScript syntax: expor ...

Password validations are a key feature of reactive forms

Currently, the sign-up button only becomes enabled if the signup form is valid. However, I am facing an issue where the button is getting enabled even when the password and confirm password fields do not match. I suspect there might be a problem with my i ...

Tutorials on transferring selected option data to a component

My JSON data is structured like this: Whenever I choose an option, I want to pass the values (code and description) from the JSON object to the component. nameList= [ { "code": "1", "description": "abc" }, { "code": "123", "descript ...

Unable to store the output of an asynchronous function in an object

When I manage to fix it, I'll be home. The current issue is saving the result from an async function. If I do a console.log after that function, I receive the translated value. However, a few moments later when I check how my verbs look like after bei ...

Can you explain the purpose of the MomentInput type in ReactJS when using TypeScript?

I am currently facing an issue where I need to distinguish between a moment date input (material-ui-pickers) and a normal text input for an event in my project. const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => { const i ...

I seem to be invisible to the toggle switch

I currently have a toggle button that controls the activation or deactivation of a tooltip within a table. Right now, the tooltip is activated by default when the application starts, but I want to change this so that it is deactivated upon startup and on ...

conditional operator that compares values in router events

As I examine an object, links = { link1: 'page1', link2: 'page2', link3: 'page3', link4: 'page4', link5: 'page5', link6: 'page6' } I possess a function for retrieving t ...

Angular Service singleton constructor being invoked multiple times

I have been facing an issue with using an app-wide service called UserService to store authenticated user details. The problem is that UserService is being instantiated per route rather than shared across routes. To address this, I decided to create a Core ...

The html-duration-picker is not being displayed in the proper format

I've been working on integrating an external library that allows for inputting document length. Specifically, I'm using the html-duration-picker library, but it seems like the input functionality is not quite right for durations. Could it be th ...

React modal not closing when clicking outside the modal in Bootstrap

I recently utilized a react-bootstrap modal to display notifications in my React project. While the modal functions correctly, I encountered an issue where it would not close when clicking outside of the modal. Here is the code for the modal: import Reac ...

FireStore mock for Angular service testing that can be reused by Jasmine

I am in the process of creating a reusable Firestore mock for testing various Angular services. The structure of my services is as follows: @Injectable({ providedIn: 'root', }) export class DataSheetService { dataSheetTypesDbRef: AngularFires ...

How can I delay the loading of a lazy loaded module in Angular until certain data is resolved from an API call?

How can I preload data before loading a lazy module in Angular? I attempted using app_initializer, but it didn't work due to an existing app_initializer in AppModule. Is there a different approach to achieve this? ...

React 18 update causes malfunctioning of react-switch-selector component

I'm facing an issue where the component is not rendering. I attempted to start a new project but it still didn't work. Is there a solution to fix this problem or should I just wait for an update from the original repository? Encountered Error: ...

Utilizing conditional binding with ngModel in Angular 5

In my Angular 5 project, I am facing some issues. I have two models called Person and Employee where Employee inherits from Person and has its own attributes. In the HTML file of my component, I created a form with several input fields: <input type="te ...

Encountered a bun runtime error stating "Possibly require an `extends React.JSX.IntrinsicAttributes` constraint for this type parameter."

I have a good understanding of ReactJS, but this topic seems to be more advanced. I am working with generics in TypeScript and have the following code: export const withPopover = <T,>(WrappedComponent: React.ComponentType<T>) => { const ...

Techniques for invoking the parent function from a child button

Imagine having a versatile component named ButtonComponent that needs to be used in different parts of the application. To ensure maximum flexibility, the component is designed as follows: button.component.ts import { Component, ViewEncapsulation, Input, ...

Angular is able to successfully retrieve the current route when it is defined, but

Here's the code snippet I am working with: import { Router } from '@angular/router'; Following that, in my constructor: constructor(router: Router) { console.log(this.router.url); } Upon loading the page, it initially shows the URL a ...