0
interface type1 {
    key1: string;
    key2: string;
    key3?: type3;
}

interface type2 {
    key1: string;
    key2: string;
    key5: string;
    key6: number;
}

interface type3 { 
    key5?: string;
    key6?: number;
}

const obj1: type1 = <type1>{};

const obj2: type2 = {
    key1: 'hi',
    key2: 'hello',
    key5: 'Hola',
    key6: 123
};

const obj3: type3 = <type3>{};

const array1: (keyof type2)[] = ['key1', 'key2'];
const array2: (keyof type3)[] = ['key5', 'key6'];


array1.forEach((key: keyof type2) => {
    obj1[key] = obj2[key]; /* Error occurred while adding value */
});

array2.forEach((key: keyof type3) => {
    obj3[key] = obj2[key]; /* Error occurred while adding value */
});

obj1.key3 = obj3;

console.log(obj1);

I have 3 objects of different types but some keys are common in objects. I want to add values dynamically from one object to another. I've added the code what I tried till now.

Is there any way to achieve it. Practically I've more keys than what I've put on the example. assigning them one by one will be huge and inefficient.

Thanks in advance.

4
  • did you tried key1: any; instead of key1: string; Commented Dec 4, 2019 at 7:39
  • @HaSnenTai I don't want to use type any in my code. With type any I can assign the values directly without error. Commented Dec 4, 2019 at 7:40
  • So you want to copy only the common properties from a source to a target object if I interpret the example correctly. Also, you want get rid of array1, array2 and don't manually define those keys? Commented Dec 4, 2019 at 9:44
  • @ford04 What you interpret it correct, only one correction I want to use array1 and array2 to define what property I want to retrieve. Type of these arrays can be changed in order to achieve the goal. Commented Dec 4, 2019 at 10:26

2 Answers 2

1

Here is a workable solution with minimal adjustments to your code (Playground):

const obj1: type1 = {} as type1;
const obj2: type2 = { key1: 'hi', key2: 'hello', key5: 'Hola', key6: 123 };
const array1 = ['key1', 'key2'] as const

array1.forEach(<K extends keyof (type1 | type2)>(key: K) => {
  obj1[key] = obj2[key]; 
});

// same with 2nd case (obj2, obj3, array2)

We can define array1 and array2 as tuples with const assertion, no need to annotate an explicit type.

In order to get the computed property access with both obj1 and obj2 to work, the key has to be declared as generic type parameter K with constraint K extends keyof (type1 | type2) (means, restrict to all common properties of type1 and type2). See this answer for an explanation of issues with computed property access with union key types and why generics are necessary.

Object spread is a second alternative, where the types get a bit easier (Playground):

const obj1: type1 = {} as type1;
const obj2: type2 = { key1: 'hi', key2: 'hello', key5: 'Hola', key6: 123 };

const obj1New = {
  ...obj1,
  ...(['key1', 'key2'] as const).reduce((acc, cur) =>
    ({ ...acc, ...{ [cur]: obj2[cur] } }), {} as type1),
}

// same with 2nd case (obj2, obj3, array2)
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot. You're a life saver :).
0

You can try in operator to check if the key exists inside an object before assignment:

array1.forEach((key: keyof type2) => {
    if(key in obj1)
       obj1[key] = obj2[key]; /* Error occurred while adding value */
});

array2.forEach((key: keyof type3) => {
    if(key in obj3)
       obj3[key] = obj2[key]; /* Error occurred while adding value */
});

1 Comment

Not fixing the issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.