Finding the key type in an interface

Here is a challenge...

This is the code snippet from titleBarContainer.tsx:

function TitleBarContainer() {
    const systemData = useSelector((state: RootState) => state.counter.systemData)
    const dispatch = useDispatch()

    const onChangeSystemData = useCallback(
        (key: keyof SystemState, value: SystemStateType) => {
            let tempSystemData = Object.assign({}, systemData)

            tempSystemData[key] = value // It's not working as expected, but that's not the main issue.
            dispatch(changeSystemData(tempSystemData))
        },
        [dispatch, systemData]
    )
}

This is the content of system.d.ts file:

interface SystemState {
    title: TitleStateType
    windowState: WindowStateType
    language: LanguageStateType
    mode: ModeStateType
}

type TitleStateType = string
type LanguageStateType = 'ko-KR' | 'en-US'
type WindowStateType = 'normal' | 'minimize' | 'maximize' | 'fullscreen'
type ModeStateType = 'admin' | 'user'

type SystemStateType = TitleStateType | WindowStateType | LanguageStateType | ModeStateType

Within the onChangeSystemData Function, I would like to have a specific type for 'value'.
For instance, if 'key' is 'normal', I expect 'value' to be of type WindowStateType rather than SystemStateType.

I attempted to use generic types. Below is the approach I tried:

Prior version of titleBarContainer.tsx (which did not work):

function TitleBarContainer() {
    const systemData = useSelector((state: RootState) => state.counter.systemData)
    const dispatch = useDispatch()

    const onChangeSystemData<SystemState> = (key, value) => {
            let tempSystemData = Object.assign({}, systemData)
            tempSystemData[key] = value
            dispatch(changeSystemData(tempSystemData))
        }
}

Prior version of system.d.ts:

interface SystemState {
    title: TitleStateType
    windowState: WindowStateType
    language: LanguageStateType
    mode: ModeStateType
}

type TitleStateType = string
type LanguageStateType = 'ko-KR' | 'en-US'
type WindowStateType = 'normal' | 'minimize' | 'maximize' | 'fullscreen'
type ModeStateType = 'admin' | 'user'

type SystemStateType = TitleStateType | WindowStateType | LanguageStateType | ModeStateType

interface InternalState<T> { (key: keyof T, value: T[keyof T]): void }

It seems quite complex to me... Any suggestions or solutions would be greatly appreciated.

Answer №1

To understand this code better, you simply need to extract the key:

interface SystemState {
  title: TitleStateType
  windowState: WindowStateType
  language: LanguageStateType
  mode: ModeStateType
}

type TitleStateType = string
type LanguageStateType = 'ko-KR' | 'en-US'
type WindowStateType = 'normal' | 'minimize' | 'maximize' | 'fullscreen'
type ModeStateType = 'admin' | 'user'

type SystemStateType = TitleStateType | WindowStateType | LanguageStateType | ModeStateType

type InternalState<T> = <Key extends keyof T>(key: Key, value: T[Key]) => void


const onChangeSystemData: InternalState<SystemState> = (key, value) => {}

onChangeSystemData('windowState','minimize') // ok
onChangeSystemData('windowState','minimize222') // expected error

Playground

Similar question

Why does not define

interface InternalState<T> { <Key extends keyof T>(key: keyof T, value: T[Key]): void 
trigger an error?

The reason is that interface InternalState<T> declares the function as a method, and methods in TypeScript are bivariant. This behavior is intentional and allows for compilation if method parameters can be assigned to passed arguments and vice versa. Although it may seem convenient, it is considered unsafe and should be used cautiously.

Additionally, feel free to explore more TypeScript examples on my dedicated blog

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

Developing forms in Angular 5 involves the decision of either constructing a specific model for the form group inputs or opting for a more generic variable with two

As a newcomer to Angular, I've noticed that most courses and tutorials recommend using a model or interface for form data. However, I have found it more efficient and straightforward to just use a generic variable with two-way data binding. Could som ...

Showing an error message upon submission in Angular 4 according to the server's response

Struggling for hours to display an error message when a form submits and returns an error status code. The solution seems elusive... In the login form component below, I've indicated where I would like to indicate whether the form is valid or invalid ...

Integrate incoming websocket information with state management in React

I am facing a challenge in creating a timeseries plot with data obtained from a websocket connection. The issue arises when new values overwrite the previously stored value in the state variable. const [chartData, setChartData] = React.useState(null) Cu ...

The AuthGuard (Guard decorator) is unable to resolve its dependencies according to Nest

My AuthGuard is responsible for checking the JWT token in controllers. I am trying to use this Guard in controllers to verify authentication, but I encountered the following error: Nest cannot resolve dependencies of the AuthGuard (?, +). Please ensur ...

Resolve the clash between Jest and Cypress within a React application developed using TypeScript

Encountering a conflict in the React app after installing Cypress with TypeScript. Despite trying to resolve it using GitHub solutions, the issue persists. I am sharing all configuration files in hopes that someone can identify the problem. cypress/tsconfi ...

Having trouble with Angular 2 and ng2-file-upload when trying to load it using SystemJS

Currently, I am utilizing systemJS for package management in my project. In order to configure systemJS, I have included the following lines in the configuration file: { map: { 'ng2-file-upload': 'node_modules/ng2-file-upload' }, p ...

Simplify a function by lowering its cyclomatic complexity

This particular function is designed to determine whether a specific cell on a scrabble board qualifies as a double letter bonus spot. With a cyclomatic complexity of 23, it exceeds the recommended threshold of 20. Despite this, I am unsure of an alterna ...

Tips for dynamically implementing a pipe in Angular 5

In my Angular application, I have implemented a filter using a pipe to search for option values based on user input. This filter is applied at the field level within a dynamically generated form constructed using an ngFor loop and populated with data from ...

Guide to Implementing StoreApi in Zustand LibraryLearn how to utilize Store

While reading the documentation for zustand, I came across a useful piece of information. In addition to the standard `set` and `get` parameters, there is an extra parameter called `api` in the StateCreator function. Check out the example below: import cr ...

Even with the use of setTimeout, Angular 5 fails to recognize changes during a lengthy operation

Currently, I am facing an issue with displaying a ngx-bootstrap progress bar while my application is loading data from a csv file. The Challenge: The user interface becomes unresponsive until the entire operation is completed To address this problem, I a ...

As a quirk of TypeScript, it does not allow for returning a Tuple directly and instead interprets it as an Array

I need assistance with adding type-safe return to a general function created by a previous developer. Here is the current syntax: export function to(promise:Promise<any>) { return promise .then(data => [null, data]) .catch(err => [ ...

Stop the ion-fab-list from automatically closing when an element is selected within it

I'm having trouble getting a form to stay visible when a fab is clicked in my Ionic 4 app. Every time I click on a fab or another component within the ion-fab-list, the ion-fab-list automatically closes. How can I prevent this from happening and keep ...

Determining in Angular 8 whether a value has been altered by a user or by a method call

Within my select element, the value is currently being assigned through an ngOnInit call. Here is an example of the HTML code: <select name="duration" [(ngModel)]="exercisePlan.duration" (ngModelChange)="onChange($event)"> <option *ngFor="l ...

The object in an Angular 11 REACTIVE FORM may be null

I am looking to incorporate a reactive form validation system in my application, and I want to display error messages based on the specific error. However, I am encountering an error that says: object is possibly 'null'. signup.component.html &l ...

What is the best way to populate empty dates within an array of objects using TypeScript or JavaScript?

I am trying to populate this object with dates from today until the next 7 days. Below is my initial object: let obj = { "sessions": [{ "date": "15-05-2021" }, { "date": "16-05-2021" }, { "date": "18-05-2021" }] } The desired ...

Error: The variable __WEBPACK_EXTERNAL_MODULE_XX__ has not been defined

A unique npm package called our-map has been developed utilizing TypeScript, webpack, and the ArcGIS JS API to encapsulate an esri map within a React component. The functionality of the module has been verified through testing on a dedicated page within th ...

The Relationship Between Typing Variables and Generic Types in Functions

I need help implementing a specific function type: type TestType<T extends HTMLElement> = (input: T) => React.Ref<T>; I have a variable that I want to be typed with the above type for strict type guarantees on the return type: const Test ...

How to display specific JSON objects that meet particular criteria in HTML cards using Ionic and Angular?

As a beginner in Ionic/Angular, I am attempting to fetch data from a JSON file and display it using cards in the HTML. The JSON contains numerous objects that are either marked as "deTurno == true" or "deTurno == false". Here is what I have so far: publi ...

Discovering the Type Inference of Function Composition Method (Chaining) in TypeScript

I'm working on implementing a function that can add a chainable method for function composition. Here's what I have so far: Also see: TypeScript playground { const F = <T, U>(f: (a: T) => U) => { type F = { compose: <V ...

Using Angular Form Builder to assign a value depending on the selected option in a dropdown menu

My approach to Angular Form Builder initialization includes a group that looks like this: contactReason: this.formBuilder.group({ description: '', source: this.sourceType() }) For the 'description' field, I hav ...