Create an array with individual key-type pairs for each generic element, then iterate through the array

Consider the enum and type declarations in the code below:

enum MyEnum {
    FIRST,
    SECOND
};

type MyType = {
    firstKey: string | null,
    secondKey: boolean,
    thirdKey: MyEnum
}

Next, a variable is declared using the type as follows:

let globalObject: MyType = {
    firstKey: "String",
    secondKey: false,
    thirdKey: MyEnum.FIRST
}

Based on the solution provided in a different post, a generic type is created:

type MainFormDataField<T extends MyType> = {
  [K in keyof T]: {
    sKey: K;
    vValue: T[K];
  };
}[keyof T];

A function is intended to use this type to assign values to specific keys of an object without direct modification. The function should execute certain logic before and after changing any value in the object. However, when passing an array of objects to the function, the type of the value property behaves differently inside the function compared to outside.

function setSomeValue(elements?: MyFieldType<MyType>[]) {
    if(!elements) {
        // Alternative logic
        return;
    }

    // Logic before value changes

    for (const element of elements) {
        globalObject[element.key] = element.value; // Type 'string | boolean | MyEnum | null' is not assignable to type 'never'. Type 'null' is not assignable to type 'never'.
    }

    // Logic after value changes
}

setSomeValue([{key: "secondKey", value: false}, {key:"thirdKey", value: false}]) // Type 'false' is not assignable to type 'MyEnum'.

The challenge is to resolve this issue. How can it be done?

TS Playground

Answer №1

The compiler is currently unable to process "correlated union types" as outlined in ms/TS#30581. However, there is a recommended refactor proposed in ms/TS#47109, which involves transitioning to generics. This suggests introducing an additional function specifically for setting a single field. This function will receive generic parameters that are restricted to keys of MyType. By employing the type structure mentioned below, the element argument will be accepted:

type SetArgs<T extends keyof MyType> = {
  [K in T]: {
    key: K;
    value: MyType[K];
  };
}[T];

const set = <T extends keyof MyType>(obj: MyType, element: SetArgs<T>) => {
  obj[element.key] = element.value;
};

Utilizing generics prevents the compiler from narrowing the type. For instance, in the set function, the element.key no longer displays specific values from the union but rather a generic version, which aligns with our objectives.

Example of usage:

function setSomeValue<T extends MyFieldType<MyType>>(elements?: T[]) {
  if (!elements) {
    return;
  }

  for (const element of elements) {
    set(globalObject, element); // no error
  }
}

Looks promising!

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

What is the best way to integrate @uirouter in the Angular/sampleapp project?

Having trouble configuring the angular/sampleapp to work with @uirouter. Is the systemjs.config.js file set up incorrectly to include @uirouter? 1) Run npm i -S @uirouter/angular 2) Add the following line to the map section in systemjs.config.js ' ...

Unable to utilize MUI Dialog within a ReactDOMServer.renderToStaticMarkup() call

I recently started using the DIALOG component for the first time, expecting it to seamlessly integrate into my setup. However, much to my disappointment, it did not work as expected. After spending a considerable amount of time troubleshooting the issue, I ...

Exploring the pitfalls of a dried-out network of canals

As a beginner in the world of coding, I am delving into my first real code project. My goal is to develop a program that can identify dead ends in a skeletonized 3D structure and mark their positions accordingly. The challenge lies in handling the situatio ...

What is the best way to transfer a variable from an @Input property to a service within an Angular2 component?

I'm tackling what seems like a simple task, but I'm struggling to figure it out. My issue is this: How can I successfully pass a variable from @Input to a service in an Angular2 component? (Code has been simplified) This is my current component ...

What is the best way to change the value in an object when the id matches?

How can I update the title within the data object when the id matches? const data = { "0": { "id": 1912, "title": "Books", }, "1": { "id": 1958, "t ...

Tips for preventing duplicate imports in Sass with the @use rule in Webpack

My sass modules have the ability to import each other as shown in the examples below: // LinearLayout.scss @mixin LinearLayout { ... } linear-layout { @include LinearLayout; } // ScrollView.scss @use "LinearLayout" as *; @mixin ScrollView { ...

Calculating numbers with Math.ceil will result in an increase of 1

After using Math.ceil, one value was rounded up to 50 and the other to 80. However, when I added these two values together, the result unexpectedly turned out to be 131. console.log(Math.ceil(e.currentTarget.clientHeight) // 50 console.log(Math.ceil(e.cu ...

When the child component's form is marked as dirty, the parent component can access it

I have implemented a feature in my application that notifies users about pending changes on a form before they navigate away. Everything works as expected, but I have a child component with its own form that needs to be accessed by the guard to check if i ...

Do not directly change a prop's value as it will be replaced when the parent component re-renders. Use v-form instead

I'm currently in the process of developing an app using nuxt along with vuetify 2.x, and I keep encountering a specific error message: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Inste ...

Preserve final variable state - Angular

My function looks like this: flag: boolean = false; some_function(){ var foo = some_num_value; var bar = foo; // Storing value in a separate variable if(this.flag){ v ...

I want my Angular 2 application to redirect to the appropriate page when a user who is logged out attempts to access a page that requires them to be logged in

When a user is logged out in Angular 2 router and they try to navigate to a page that requires them to be logged in, I need the app.ts file to redirect them. I am utilizing typescript along with angular 2. Oddly enough, the redirection works for certain ...

Utilizing the validator in Vue with the setup script, TypeScript, and the composition API

While working on some code from a tutorial, I came across the challenge of implementing a validator in a similar fashion to the example provided. My task involves utilizing the script setup, typescript, and the composition API. props: { image: { ...

Generate a 2D array resembling a grid

I have limited experience with Java and am facing a project with tight deadlines. I need assistance with the following class: public static void getAllDataDB1() // Retrieving data from the "bank1" database { try { MetaData1 ...

What steps can I take in JavaScript to assign a value of 0 to values[1] in order to prevent receiving NaN as the output

I'm currently working on a program that calculates the sum of 6 input values, but I've encountered an issue where if a value is missing (for example, only providing 5 values), the result becomes NaN. I attempted to address this by assigning empty ...

Unexplained Reference Error in Next.js Typescript: Variable Accessed before Initialization

I am currently working on an admin website and encountered the error Block-scoped variable used before its declaration.. I will provide details using images and code. This is my first time seeking help on StackOverflow. Error Message: Block-scoped variab ...

Working with an array of objects with varying shapes and validating them

I have dedicated quite a bit of time to this task and would greatly appreciate some assistance. I am in need of a component (a function) that can accept an array of objects while also validating the properties of these objects. Here are the interfaces and ...

Issue: The module '@nx/nx-linux-x64-gnu' is not found and cannot be located

I'm encountering issues when trying to run the build of my Angular project with NX in GitHub Actions CI. The process fails and displays errors like: npm ERR! code 1 npm ERR! path /runner/_work/myapp/node_modules/nx npm ERR! command failed npm ERR! c ...

C++ sentence-derived array structure

Possible Repetition: Splitting a string in C++ How can I store a series of words separated by spaces in an array? For instance, if I have the following sentence: "I enjoy coding" and declare this array: string myWordsArray[3] I intend to assign ...

The array is acting strangely and not functioning as expected

I am currently working with express, node, and mongoose. When I access my mongoDB database and log it to the console, I get the following array: module.exports ={ stories: function(req, res, next){ Story.find(function(err, stories){ if(err) ...

The parameter "disabled=false" is not functioning properly in TypeScript 2.1

Struggling to deactivate a field by accessing the element ID in TypeScript 2.1. Came across this syntax for TypeScript 1.5, but unfortunately, it doesn't seem to work in 2.1. Any assistance would be greatly appreciated. ( document.getElementById(&apo ...