What in the world is going on with this Typescript Mapped type without a right-hand side?

I encountered a situation where my React component had numerous methods for toggling boolean state properties. Since these functions all did the same thing, I wanted to streamline the process by creating a common function for toggling properties.

Each method followed this structure:

toggleProperty() {
    this.setState(previous => ({
        myProperty: !previous.myProperty
    }))
}

To simplify things, I devised a universal method that could be invoked with the relevant context:


/** Filters out keys of B that doesn't have the same type of T **/

type FilterOutUnmatchedType<B extends Object, T extends any> = {
    [K in keyof B]: B[K] extends T ? K : never;
}[keyof B];


private StateToggler(this: Configurator, property: FilterOutUnmatchedType<ConfiguratorState, boolean>) {
        this.setState((previous) => ({
            [property]: !previous[property]
        });
    }

In this method, my goal was to only accept boolean properties from the state object. While FilterOutUnmatchedType served its purpose, I encountered an error in Visual Studio Code:

Argument of type '(previous: Readonly<ConfiguratorState>) => { [x: string]: boolean; }' is not assignable to parameter of type 'ConfiguratorState | ((prevState: Readonly<ConfiguratorState>, props: Readonly<ConfiguratorProps>) => ConfiguratorState | Pick<...>) | Pick<...>'.
  Type '(previous: Readonly<ConfiguratorState>) => { [x: string]: boolean; }' is not assignable to type '(prevState: Readonly<ConfiguratorState>, props: Readonly<ConfiguratorProps>) => ConfiguratorState | Pick<...>'.
    Type '{ [x: string]: boolean; }' is not assignable to type 'ConfiguratorState | Pick<ConfiguratorState, (omitted, keyof ConfiguratorState - basically))>'

It appeared that the code was considering [property]: boolean too generic, even though property was within keyof ConfiguratorState.

After multiple attempts to resolve this issue, I stumbled upon a solution that seemed to work without clear explanation. The syntax involved a casting as part of Mapped Types:

this.setState(
    (previous) => ({
        [property]: !previous[property]
    } as { [K in keyof ConfiguratorState] })
);

This usage of Mapped Types caught me off guard, as I initially expected a right-hand side assignment. Surprisingly, omitting the RHS like ConfiguratorState[K] resulted in the desired outcome. Though perplexing, the code executed correctly.

If anyone can shed light on this concept and direct me to additional resources, I would greatly appreciate it!

Answer №1

In cases where a right hand side is not provided, the type is automatically assumed to be any. Therefore,

{ [K in keyof ConfiguratorState] }
can be considered as
{[K in keyof ConfiguratorState]: any}
, or
Record<ConfiguratorState, any>
. It's important to note that when noImplicitAny is enabled, TypeScript will generate an error due to the implied any type.

Check out this Playground link for demonstration.

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

What is the method for accessing the string value of a component's input attribute binding in Angular 2?

In my Angular2 application, I have a straightforward form input component with an @Input binding pointing to the attribute [dataProperty]. The [dataProperty] attribute holds a string value of this format: [dataProperty]="modelObject.childObj.prop". The mod ...

Error: "Reflect.getMetadata function not found" encountered during execution of Jenkins job

My Jenkins job is responsible for running tests and building an image. However, I am encountering issues with the unit tests within the job. task runTests(type: NpmTask) { dependsOn(tasks['lintTS']) args = ['run', 'test&ap ...

Convert TypeScript-specific statements into standard JavaScript code

For my nextjs frontend, I want to integrate authentication using a keycloak server. I came across this helpful example on how to implement it. The only issue is that the example is in typescript and I need to adapt it for my javascript application. Being u ...

Typescript typings for child model/collection structures

I have encountered an issue while trying to implement a Model/Collection pattern with various typings. Both the Model and Collection classes have a method called serialize(). When this method is called on the Collection, it serializes all the Model(s) with ...

I am configuring Jest in my Vite and TypeScript-powered React project

I am having trouble with the relative path of the file I imported in App.test.tsx. It keeps showing me this error message: Cannot find module '@/components/items/card.tsx' from 'src/__tests__/App.test.tsx' Below is the code snippet: // ...

How can I make TypeScript properly export function names for closure-compiler?

Here is the TypeScript code I am working with: namespace CompanyName.HtmlTools.Cookie { export function eraseCookie(name:string, path:string) { createCookie(name, "", path, -1); } export function readCookie(name:string) { ...

Tips for adding and verifying arrays within forms using Angular2

Within my JavaScript model, this.profile, there exists a property named emails. This property is an array composed of objects with the properties {email, isDefault, status}. Following this, I proceed to define it as shown below: this.profileForm = this ...

Performing operations on information within a map function

While using toLocaleString within this map, I encountered an issue where only one of the payment.amount's returned formatted as currency. {props.paymentDates.map((payment, index) => ( <tr key={"payment-" + index}> <td>{i ...

Utilize Material-UI in Reactjs to showcase tree data in a table format

I am currently tackling a small project which involves utilizing a tree structure Table, the image below provides a visual representation of it! click here for image description The table displayed in the picture is from my previous project where I made ...

Adjusting image dynamically based on conditions

I need to dynamically display images on my HTML based on specific conditions using TypeScript. In my TypeScript file: styleArray = ["Solitary", "Visual","Auditory","Logical","Physical","Social","Verbal",]; constructor(){ for (var i = 0; this.sty ...

How to Override Global CSS in a Freshly Created Angular Component

My CSS skills are a bit rusty and I need some assistance with a project I'm working on. The project includes multiple global CSS files that have properties defined for different tags, such as .btn. However, these global CSS files are causing conflicts ...

Arrange an array of objects by making a nested API call in Angular

My task involves sorting an array of objects based on the response from the first API call in ascending order. The initial API call returns a list of arrays which will be used for the subsequent API call. The first API call fetches something like this: [0 ...

Tips for enabling custom object properties in Chrome DevTools

In my typescript class, I am utilizing a Proxy to intercept and dispatch on get and set operations. The functionality is working smoothly and I have successfully enabled auto-completion in vscode for these properties. However, when I switch to the chrome d ...

initiate an animated sequence upon the initialization of the Angular server

Is there a way to launch a Netflix animation after my server has started without success using setTimeout? I don't want to share the lengthy HTML and CSS code. You can view the code for the animation in question by visiting: https://codepen.io/claudi ...

Issue regarding retrieving the image using TypeScript from an external API

Hey developers! I'm facing an issue with importing images from an external API. I used the tag: <img src = {photos [0] .src} /> but it doesn't seem to recognize the .src property. Can anyone shed some light on how this is supposed to work? ...

Exploring the complexities of cyclic dependencies and deserialization in Angular

I have encountered an issue with deserializing JSON objects in my Angular project. After receiving data through httpClient, I realized that I need to deserialize it properly in order to work with it effectively. I came across a valuable resource on Stack O ...

Encountering a Next.js event type issue within an arrow function

After creating my handleChange() function to handle events from my input, I encountered an error that I'm unsure how to resolve. Shown below is a screenshot of the issue: I am currently working with Next.js. In React, this type of error has not been ...

"Dealing with cross-origin resource sharing issue in a Node.js project using TypeScript with Apollo server

I am encountering issues with CORS in my application. Could it be a misconfiguration on my server side? I am attempting to create a user in my PostgreSQL database through the frontend. I have set up a tsx component that serves as a form. However, when I tr ...

Error: Angular2 RC5 | Router unable to find any matching routes

I am currently encountering an issue with my setup using Angular 2 - RC5 and router 3.0.0 RC1. Despite searching for a solution, I have not been able to find one that resolves the problem. Within my component structure, I have a "BasicContentComponent" whi ...

NodeJS and TypeScript are throwing an error with code TS2339, stating that the property 'timeOrigin' is not found on the type 'Performance'

I am currently working on a NodeJS/TypeScript application that utilizes Selenium WebDriver. Here is an excerpt from the code: import { WebDriver } from "selenium-webdriver"; export class MyClass { public async getTimeOrigin(driver: WebDriver ...