Is it possible to assign a property value to an object based on the type of another property?

In this illustrative example:

enum Methods {
    X = 'X',
    Y = 'Y'
}

type MethodProperties = {
    [Methods.X]: {
        x: string
    }
    [Methods.Y]: {
        y: string
    }
}

type Approach = {
    [method in keyof MethodProperties]: {
        method: method
    } & MethodProperties[method]
}

//produces the anticipated outcome, but may not be optimal for every scenario

const strategy1: Approach[Methods] = {
    method: Methods.X,
    x: 'string',
};

(() => {
    if (strategy1.method === Methods.X) {
        strategy1.x = 'anotherstring';
        //does not throw an error since the compiler recognizes
        //the potential properties based on method type
    }
})();

//does not generate the expected outcome, but might be more suitable for certain situations

type Plan = {
    method: Methods
    methodProps: MethodProperties[Plan['method']]
}

const strategy2: Plan = {
    method: Methods.X,
    methodProps: {
        x: 'string',
        y: 'string',
    }
};

(() => {
    if (strategy2.method === Methods.X) {
        strategy2.methodProps.x = 'anotherstring';
        //results in an error - Property 'x' does not exist on type '{ y: string; }'
    }
})();

Playground

The desired outcome is to notify the compiler that when state.type === ActionTypes.A, then the type of state.actionProps should be ActionProps[ActionTypes.A].

Are there any feasible workarounds for this issue?

Answer №1

Are you in search of a standard solution:

enum ActionTypes {
    A = 'A',
    B = 'B'
}

type ActionProps = {
    [ActionTypes.A]: {
        a: string
    }
    [ActionTypes.B]: {
        b: string
    }
}

type State<Type extends keyof ActionProps> = {
    type: Type
    actionProps: ActionProps[Type] & ActionProps[keyof ActionProps]
}

const state: State<ActionTypes.A> = {
    type: ActionTypes.A,
    actionProps: {
        a: 'string',
        b: 'string',
    }
};

(() => {
    if (state.type === ActionTypes.A) {
        state.actionProps.a = 'anotherstring';
        //errors - Property 'a' does not exist on type '{ b: string; }'
    }
})();

Yet, TypeScript appears unable to deduce the type parameter based on the .type property value, as this functionality is typically associated with discriminated unions.

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

Call a function within a stateless component in a React application

I have a question regarding my React component. I am attempting to call the function ButtonAppBar within my stateless component, but the TypeScript compiler is throwing an error stating '{' expected. I'm unsure whether I need to pass it to m ...

Strategies for organizing your week with a calendar

Hello, I am working on creating a weekly calendar using PHP and I want to add events to the calendar like in this example. However, I am unsure how to display the events in the calendar at the correct time of day. Here is the code snippet I am currently u ...

The call function in Tween.js fails to execute after adding an EventListener

I encountered an issue while using tween.0.6.2. The following code snippet (borrowed from the tween.js Getting Started page and slightly simplified) works perfectly: createjs.Tween.get(circle) .to({x: 400}, 1000, createjs.Ease.getPowInOut ...

Handling events in React using TypeScript

Currently diving into the world of React with Typescript and encountered a challenge involving event handling using the onClick property. I have a react component displaying a list of items from an array, and I aim to log the clicked item in the console. I ...

Using Selenium: Checking for existing dropdown values and incrementing if necessary

I am currently working on automating an application using Selenium Webdriver with Java. The web application I am testing has an Add button that, when clicked, triggers the activation of a dropdown menu. Subsequent clicks on the Add button reveal additional ...

Using React - What is the best way to invoke a function from within a different function?

Imagine this scenario: class Navigation extends React.Component { primaryFun() { console.log('funn') } secondaryFun() { this.primaryFun(); } } I assumed that calling primaryFun within secondaryFun would work as expected, but instead I rec ...

What are the steps to properly build and implement a buffer for socket communication?

I have encountered an issue while converting a code snippet to TypeScript, specifically with the use of a Buffer in conjunction with a UDP socket. The original code fragment is as follows: /// <reference path="../node_modules/DefinitelyTyped/node/node ...

Typescript encounters ERROR TS1128: Expecting a declaration or statement

Having trouble with a TypeScript error in my game-details.component.ts file that I've been trying to fix for a couple of hours. It's showing up at line 26, column 54 and everything seems correct to me. Interestingly, when I press CTRL + S in my ...

I am interested in incorporating pinia state management into my Vue 3 project

I'm currently working on implementing pinia state management in Vue 3, but I've encountered the following error: Module not found: Error: Can't resolve 'src/stores/cart' in 'C:\Users\Ali Haider\theme-project&b ...

What is the best way to add custom styles to an Ext JS 'tabpanel' xtype using the 'style

Is there a way to change the style of a Ext.tab.Panel element using inline CSS structure like how it's done for a xtype: button element? { xtype: "button", itemId: "imageUploadButton1", text: "Uploader", style: { background : ' ...

Is it better to dynamically generate HTML elements or to just directly paste complete fragments in the code?

After manipulating the DOM and injecting AJAX content, I often find myself filling in the new content into a copied HTML fragment, then populating it with the updated information before using $().html() to insert the modified code back into the DOM. The ex ...

Looking to extract data from a Json object and add it into a table

<!DOCTYPE html> <html> <head> <script type="text/javascript"> function displayJsonData() { var jsonData = { "cars": [ '{"model":"Sentra", "doors":4, "features":["hi"," ...

What is the method for attaching multiple listeners to an element?

For example: v-on:click="count,handle" I posted this question in the Vue gitter channel, but received advice to use a single listener that triggers others. If using one listener is the recommended approach, I am curious to understand why. Is having multi ...

Refine JSON data by selecting only distinct key/value pairs

My JSON object has the following structure: var theSchools = { Bradley University: "bru", Knox College: "knox", Southern Illinois University Edwardsville: "siue",… } I am trying to find a way to retrieve the school name (key) based on the schoo ...

Developing with Phonegap Build: A Guided Process

With all the conflicting information available, I am seeking clarity on this topic. Objective: To create and enhance a Phonegap app using Phonegap Build. 1) My preference is to utilize Phonegap Build without needing to install Android and iOS SDKs. 2) I ...

The button component in my React application is not functioning as expected, despite utilizing the useState and useEffect hooks

I'm having trouble with my Button not working, even though I am using useState and useEffect Check out the code below: import React, { useState, useEffect } from "react"; // import Timeout from "await-timeout"; import ...

A guide to playing a series of audio files in succession using the Ionic Media plugin

I have been attempting to create a playlist of multiple audio files using the Ionic media plugin from here. However, I am struggling to achieve this without resorting to using a timeout function. Here is my current approach: playOne(track: AudioFile): Pr ...

What is causing this code to malfunction?

Currently delving into the world of Ajax, I've been following a tutorial and have crafted the script below: <!DOCTYPE html> <html> <head> <script type="text/javascript"> function MyFunction(){ var xmlhttp; if(windo ...

modifying the click state using a variable in jquery

Something feels off about my approach to this task. I currently have a series of hyperlinks, and when they are clicked, they go through a short sequence before changing states. When clicked again, they revert to their original state. var favourites = fun ...

Using a Button component as a TableCell in a material-ui Table

Hey there! I'm looking for some assistance in adding buttons as TableRowColumns in the material-ui Table. I'm working on implementing an approval system to approve or reject user requests, and I thought presenting them in a tabular format would b ...