What is the best method for keeping two properties in a Typescript object in sync in a flexible manner?

I am looking to illustrate the concept that a property of an object is "in sync" with another property within the same object.

Consider a hypothetical type called Widget, which represents a UI component storing a specific data type.

type Widget = {
  id: string
  type: string
}

const datepicker: Widget = {
  id: "datepicker",
  type: "string" // stores an ISO string
}

const numberpicker: Widget = {
  id: "numberpicker",
  type: "number"
}

Now, let's introduce a Config object, which specifies that certain inputs have a particular type and are supported by a specific widget. The goal is to ensure that only compatible widgets are used.

type ConfigItem = {
  name: string
  type: string
  widget: Widget
}

type Config = Array<ConfigItem>;

const config: Config = [{
  name: "birthdate",
  type: "string",
  widget: datepicker, // This is valid because a datepicker supports a string
}, {
  name: "age",
  type: "number", 
  widget: numberpicker // This is valid because a numberpicker supports a number
}, {
  name: "numberPets",
  type: "number", 
  widget: datepicker // This is invalid as a datepicker cannot support a number
}]

I am uncertain about how to properly articulate this requirement or if it is feasible... I aim to generalize this idea beyond just this example. Thank you.

Answer №1

Give this a shot

interface Widget = { id: string } & ({ type:"string" } | { type:"number" })

const datepicker: Widget = {
  id: "datepicker",
  type: "string" // holds an ISO string
}

const numberpicker: Widget = {
  id: "numberpicker",
  type: "number"
}

interface ConfigItem = { name:string } & ({ type:"string", widget: { type:"string" } } | { type:"number", widget: {type:"number"} })

interface Config = Array<ConfigItem>

const config: Config = [{
  name: "birthdate",
  type: "string",
  widget: datepicker, // Valid as datepicker handles strings
}, {
  name: "age",
  type: "number", 
  widget: numberpicker // Valid as numberpicker manages numbers
}, {
  name: "numberPets",
  type: "number", 
  widget: datepicker // Not valid since datepicker does not handle numbers
}]

https://i.sstatic.net/AnKAA.png playground

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

Advantages of incorporating types through imports versus relying solely on declaration files in Typescript

We are currently in the process of switching from plain JavaScript to TypeScript. One aspect that I personally find frustrating is the need to import types. In my opinion, importing types serves no real purpose other than cluttering up the import section ...

The pagination feature in ag-grid is malfunctioning, causing it to initially send a request to

Upon clicking the search button, a server call will be made to retrieve results and display them in the ag grid. The server will only return the specified number of records based on the pagination details provided with each click. Despite implementing the ...

There seems to be an issue with the useReducer value not updating when logging it in a handleSubmit function

I'm currently incorporating useReducer into my Login and Register form. Interestingly, when I attempt to log the reducer value, it only displays the default value. However, if I log it within the useEffect hook, it functions correctly. Below is a sn ...

Angular - Implementing *ngIf based on URL parameters

Is it possible to display an element based on specific queryParams included in the URL? For example: ngOnInit() { this.route.queryParams.subscribe(params => { console.log(params); }); } If I want to achieve something similar to this: ...

Bringing a JavaScript function into a TypeScript file results in it being treated as a namespace

Trying to bring a vanilla JavaScript function into a TypeScript file within a React Native app has presented some challenges. The import process goes smoothly when working with JS, but switching to TS triggers the error message: Cannot use namespace &apos ...

Encountering difficulty in removing a record from the database utilizing Prisma with Next.js API routes

Currently, I am in the process of developing a Todo manager using Next.js 13, Prisma, and MySQL. In order to include a feature that allows users to delete a todo item, I have implemented the use of a Link tag for the delete button within my code: ... <L ...

After performing the `ng build --prod` command in Angular 4, deep linking functionality may not

I have a requirement to display different screens in my Angular application based on the URL pasted by the user in the browser: http://localhost/screen1 (should show screen1) http://localhost/screen2 (should show screen2) To achieve this, I have set up ...

Vue Error: The method "reduce" is not a function

Currently implementing Vue.js with Typescript and aiming to utilize reduce for summing up the values of desktopCnt and mobileCnt from the deviceCount array to display their total numbers. The deviceCount array structure is as follows: [ { " ...

What is the best way to restrict a React input field to have values within the minimum and maximum limits set by its

As a newcomer to React, I am working on restricting my input to values between -10 and 10. Currently, the input is set up to accept any value, and I am utilizing hooks like useState and useEffect to dynamically change and set the input value. My goal is ...

Error in GraphQL query: specified argument is mandatory, yet not supplied

I recently started learning about graphql and encountered an issue with my query. Here is the code I am using: { product { id } } "message": "Field "product" argument "id" of type "String!" is requir ...

Replacing a push operation in JavaScript with a splice operation

Upon entering a screen, 5 promises are automatically loaded using promise.all. The issue is that they are executed in a random order, and within each function, I use a push to store the information. The problem arises when I need to change the push to a s ...

Have the quantities in the orderState been recently updated?

Whenever I modify the quantity of an order item, does it result in creating a duplicate entry for that particular item in the state every time? For instance, if the action.payload.indexNumber is 2 and action.payload.quantity is set to 100. This snippet s ...

How come the hook keeps triggering endlessly in a loop when I try to pass the updated props?

I've encountered an issue with a custom hook I created for making HTTP requests. The problem is that the request seems to be firing in an endless loop, and I'm unsure of what's causing this behavior. My intention is for the request to only t ...

What is the best way to access the userPass value from an array of objects in Angular 7?

How can I retrieve the userPass value from an array of objects using Angular 7? I am looking to access the userPass property value from an array of objects. I have a variable named auth of type any. The auth variable contains an array of objects. I wan ...

Access specific files within a workspace in VS Code with read-only permissions

Currently, I am engaged in a typescript project within Visual Studio Code. In my workflow, a gulp task is responsible for transferring code to a designated folder. The files copied will be utilized by corresponding files located in the destination folder t ...

Having trouble with TypeScript error in React with Material-UI when trying to set up tabs?

I have developed my own custom accordion component hook, but I am encountering the following error export default const Tabs: OverridableComponent<TabsTypeMap<{}, ExtendButtonBase<ButtonBaseTypeMap<{}, "button">>>> Check ...

Encountering an issue accessing a property retrieved from a fetch request in TypeScript

I am currently dealing with the property success defined in the API (reCAPTCHA). /** * The structure of response from the veirfy API is * { * "success": true|false, * "challenge_ts": timestamp, // timestamp of the challen ...

Transition from using ReactDOM.render in favor of asynchronous callback to utilize createRoot()

Is there a React 18 equivalent of this code available? How does it handle the asynchronous part? ReactDOM.render(chart, container, async () => { //code that styles some chart cells and adds cells to a worksheet via exceljs }) ...

New Entry failing to appear in table after new record is inserted in CRUD Angular application

Working with Angular 13, I developed a basic CRUD application for managing employee data. Upon submitting new information, the createEmployee() service is executed and the data is displayed in the console. However, sometimes the newly created entry does no ...

Encountering an error when attempting to iterate over an undefined property using an API

I am trying to fetch all classes and their assignments from Google Classroom. I successfully used Google's example code for listing the classes, but had to write my own code for listing the assignments. While the code runs as expected and lists the as ...