Is it possible to use various mapped types to define the key/value pairs of an object, even if only one value

Struggling to configure the type correctly in this scenario.

I aim to define an object where each top-level key corresponds to a string from one union, with its value being a nested object consisting of keys from another union and values that can be strings from the first union (similar to a state machine).

For instance:

type Status = 'idle' | 'loading' | 'error' | 'view'
type Actions = 'search' | 'search_success' | 'search_failure'

const app = {
  idle: {
    search: 'loading'
  },
  loading: {
    search_success: 'view',
    search_fail: 'error',
  },
  error: {
    search: 'loading'
  }
  view: {
    search: 'loading'
  }
}

My current typing attempts have been:

type States = { [key in Status]: { [key in Actions]: Status } };

However, this implementation is not functioning as expected. Can someone guide me on how I could potentially utilize utility types to allow the nested object key to selectively require values from the Actions type?

Thank you!

Answer №1

I have streamlined your code for better readability.

Consider the following definition:

type Status = 'idle' | 'loading'
type State = { [key in Status]: any}

This definition is essentially equivalent to:

type State = { 
  idle: any;
  loading: any;
}

However, the code snippet below is not valid because it lacks the loading property:

const foo: State = {
  idle: true
}

To resolve this issue, you can make the properties optional as shown below:

type Status = 'idle' | 'loading' | 'error' | 'view'
type Actions = 'search' | 'search_success' | 'search_failure'

type States = { [key in Status]?: { [key in Actions]?: Status } };

const app: States = {
  idle: {
    search: 'loading'
  },
  loading: {
    search_success: 'view',
    search_failure: 'error',
  },
  error: {
    search: 'loading'
  },
  view: {
    search: 'loading'
  }
}

Try out the code on the TypeScript playground here.

Answer №2

After reviewing the solution provided by @MoshFeu, I believe it should work effectively. However, I would like to mention that a similar outcome can be achieved using a Partial:

type Status = 'inactive' | 'in progress' | 'failed' | 'completed'
type Actions = 'start' | 'success' | 'failure'

type States = { [key in Status]: Partial<{ [key in Actions]: Status }> };

const application: States = {
  inactive: {
    start: 'in progress'
  },
  'in progress': {
    success: 'completed',
    failure: 'failed',
  },
  failed: {
    start: 'in progress'
  },
  completed: {
    start: 'in progress'
  }
};

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

The image concatenation function is not functioning properly within a directive being used in an ng-repeat

This div contains an ng-repeat where I am attempting to include an image for each file. <div class = "fileslink" ng-repeat="file in files" id = "filegen" my-repeat-directive> .... ` The image is generated and displayed on page load: function fil ...

Exception in posting strings or JSON with react.js

Whenever a user clicks on the Signup button, the process I follow to create an account is as follows: Firstly, a new User entry is created in the database. createUser = () =>{ var xhr = new XMLHttpRequest(); xhr.open('POST', 'http:// ...

What is the best way to retrieve a value from a button function in order to utilize it in AJAX requests and SQL queries?

Having an edit button that allows users to change category names. When the edit button is clicked, a pop-up alert appears with an input field. Users can type in the input field, press okay, and the value should update with the input. This is the current co ...

How to retrieve an object's property within a component

Currently, my goal is to retrieve the email property from the user object {"name":"test", "email":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="582c3d2b2c182c3d2b2c7620">[email protected]</a>"} I want to achie ...

Disable vertical touchmove events to prevent scrolling vertically, while still allowing for horizontal touch and the use of buttons for scrolling

I am working on an iPad app that includes a jQuery widget with both horizontal and vertical scrolling functionality. I want to disable vertical scrolling via touch events while still allowing users to scroll vertically using buttons (such as a slider). Is ...

Tips for utilizing the .animate() method in JS/jQuery to create a reverse animation effect, moving elements from the last position to the

My question is straightforward, I have created a text animation that consists of multiple <span></span> elements within a <p> </p> for each character in my variable content string. Currently, I am using this code to animate the te ...

Switching from Vanilla JS to Vue.js, dealing with querySelector problems

Seeking assistance with transforming the following CodePen example to a Vue.js component: https://codepen.io/kjbrum/pen/qooQJJ While attempting to incorporate this.$nextTick for handling DOM manipulation, I'm encountering challenges in making it func ...

How to successfully integrate the three.js example of webgl_loader_obj_mtl.html into an ASP.NET WebForm, even when encountering issues with mtlLoader.setPath

While attempting to integrate the webgl_loader_obj_mtl.html example from three.js into an ASP.NET WebForm, I encountered an issue. Upon running the HTML, Visual Studio 2015 failed at mtlLoader.setPath. Has anyone else experienced the same problem? Addition ...

How can a service be injected in NestJs based on its interface?

I have a module named payment.module.ts with the following setup: @Module({ controllers: [PaymentController], }) export class PaymentModule {} In my payment.service.ts file, I want to utilize a service that adheres to an interface. Here is an example ...

React: the value of this.props.item has not been defined

When attempting to pass an array from one component to another and then to a third component, the item is showing up as undefined. In my App.js file, I am trying to pass this.state.searchResults to the SearchResults component. import React from 'rea ...

Encountering a type error with React Navigation 5 while transitioning between stack screens

I have encountered some TypeScript errors while using react-navigation 5. It seems that I might be making mistakes in how I am typing things or structuring the app, but I'm uncertain about the exact issue. I started off by following these guides from ...

Web application error: Karma and Webpack cannot locate Angular controller

After following a blog post on setting up an Angular project with webpack, I used an associated boilerplate on Github. Although the app is functioning properly, Karma seems to have trouble finding the controller it needs to test. // karma.config.js modul ...

Retrieve the HTML content of all children except for a specific child element in jQuery

Is there a way to utilize jQuery/Javascript for selecting the HTML content of the two <p> elements in the initial <div class="description? I'm open to using Regex as well. This specific jQuery selection is being executed within Node.js on a c ...

Displaying a variety of values based on the specific URL

I am attempting to display specific values from an array of objects based on the current URL. For example, if the URL is "localhost/#/scores/javelin," I only want to display the javelin scores from my array. Here is an example of what my array looks like: ...

Where is the appropriate location to insert a <script> tag in NextJs?

I am facing a challenge in my NextJs application when trying to include the <script> code. I attempted to add it in a .js file but it did not work as expected. In traditional React applications, we typically use the index.html file to incorporate sc ...

What are the most effective ways to manage state in form components using React?

As I delve into the realm of best practices for managing state in React components, I find myself grappling with different approaches. Initially, I crafted a form by creating a TextField component structured like this: var TextField = React.createClass({ ...

Dynamically defined type literals in Typescript

Recently, I came across an intriguing problem. I am attempting to develop a Vue.js wizard component that takes in configuration objects. The type of demo I have looks like this: type WizardConfiguration = { steps: Array<{ name: string, fie ...

Unfortunately, the Ajax functionality is not performing as expected

What am I missing? 2.php: <button id = "Text_Example">Display</button> <script src="jquery-3.1.1.min.js"></script> <script src="js_code.js"></script> js_code.js: $("#testtext").bind("click", displayNewData); functio ...

angular primeng table has a checkbox to select all checkboxes

Is there a way to check all checkboxes in a table when the checkbox in the table header is clicked? I am currently utilizing angular 12 and primeNG table for this functionality. <p-table styleClass="text-sm" [value]="value" [loading] ...

What is the solution for the error message "Unhandled Runtime Error" with the description "TypeError: videoRef.current.play is not a function"?

I am currently working on implementing custom controls for a video on a Nextjs website. When using a standard HTML <video> component, the code functions as expected and clicking the custom play button successfully plays the video. However, when I swi ...