It seems you want to extend Column instances with a formatValue property that contains the value from the corresponding Stat instance while still retaining then Item's property type.
The example below will do just that, making the value property used in the returned object's formatValue's arguments be the same type of corresponding item with the same key.
interface FormattedColumn<T, V> extends Column {
formatValue: (params: { value: V; item: T }) => string;
}
type ColumnsWithFormat<T> = { [P in keyof T]: FormattedColumn<T, T[P]> };
function extendColumns<T>(columns: Columns<T>, stats: Stats<T>): ColumnsWithFormat<T> {
const columnsWithFormat: Partial<ColumnsWithFormat<T>> = {};
for (const key in stats) {
columnsWithFormat[key] = { ...columns[key], formatValue: stats[key].formatValue };
}
return columnsWithFormat as ColumnsWithFormat<T>;
// Alternative with Object.entries.
// return (Object.entries(stats) as [keyof T, Stats<T>[keyof T]][])
// .reduce((acc, [key, stat]) => ({ ...acc, [key]: { ...columns[key], formatValue: stat.formatValue }}),
// {} as Partial<ColumnsWithFormat<T>>) as ColumnsWithFormat<T>;
}
const result = extendColumns(columns, items);
// formatValue: (params: { value: Currency; item: Item; }) => string
result.currency.formatValue({ item: { currency: 'USD', earnings: 1, id: 1, product: 'abc' }, value: 'USD' });
Answer from Daniel Gimenez on Stack OverflowCombining two TypeScript object with the same keys & different properties? - Stack Overflow
How to combine object properties in typescript? - Stack Overflow
How can I merge properties of two JavaScript objects? - Stack Overflow
Merge JavaScript objects in array with same key - Stack Overflow
Seems like this should do the trick:
var objectA = {
propertyA: 1,
propertyB: 2,
.
. // more properties here
.
propertyM: 13
};
var objectB = {
propertyN: 14,
propertyO: 15,
.
. // more properties here
.
propertyZ: 26
};
var objectC = {...objectA, ...objectB}; // this is the answer
var a = objectC.propertyA;
var n = objectC.propertyN;
Based on this article: https://blog.mariusschulz.com/2016/12/23/typescript-2-1-object-rest-and-spread
In addition, the order of the variables in the decomposition matters. Consider the following:
var objectA = {
propertyA: 1,
propertyB: 2, // same property exists in objectB
propertyC: 3
};
var objectB = {
propertyX: 'a',
propertyB: 'b', // same property exists in objectA
propertyZ: 'c'
};
// objectB will override existing properties, with the same name,
// from the decomposition of objectA
var objectC = {...objectA, ...objectB};
// result: 'b'
console.log(objectC.propertyB);
// objectA will override existing properties, with the same name,
// from the decomposition of objectB
var objectD = {...objectB, ...objectA};
// result: '2'
console.log(objectD.propertyB);
(Is there an operator that can extract the interface/type of an existing object? Is it possible?)
You should go for typeof.
type typeA = typeof objectA;
type typeB = typeof objectB;
To get them merged you can use intersection operation as basarat already pointed out.
type typeC = typeA & typeB
With Underscore.js, to merge an array of objects do:
var arrayOfObjects = [ {a:1}, {b:2, c:3}, {d:4} ];
_(arrayOfObjects).reduce(function(memo, o) { return _(memo).extend(o); });
It results in:
Object {a: 1, b: 2, c: 3, d: 4}
You should use lodash's defaultsDeep
_.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
// → { 'user': { 'name': 'barney', 'age': 36 } }
Here is one option:-
var array = [{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: ["val2", "val3"]
}, {
name: "foo2",
value: "val4"
}];
var output = [];
array.forEach(function(item) {
var existing = output.filter(function(v, i) {
return v.name == item.name;
});
if (existing.length) {
var existingIndex = output.indexOf(existing[0]);
output[existingIndex].value = output[existingIndex].value.concat(item.value);
} else {
if (typeof item.value == 'string')
item.value = [item.value];
output.push(item);
}
});
console.dir(output);
Here is another way of achieving that goal:
var array = [{
name: "foo1",
value: "val1"
}, {
name: "foo1",
value: [
"val2",
"val3"
]
}, {
name: "foo2",
value: "val4"
}];
var output = array.reduce(function(o, cur) {
// Get the index of the key-value pair.
var occurs = o.reduce(function(n, item, i) {
return (item.name === cur.name) ? i : n;
}, -1);
// If the name is found,
if (occurs >= 0) {
// append the current value to its list of values.
o[occurs].value = o[occurs].value.concat(cur.value);
// Otherwise,
} else {
// add the current item to o (but make sure the value is an array).
var obj = {
name: cur.name,
value: [cur.value]
};
o = o.concat([obj]);
}
return o;
}, []);
console.log(output);
You can complete by iterating Obj1, then Array#find from Obj2 like this.
let Obj1=[{"cols":1,"rows":2,"x":0,"y":0,SIZES:{"sizeName":"square","S1":"12","S2":"14"}},{"cols":2,"rows":3,"x":1,"y":2,SIZES:{"sizeName":"bracket","S1":"14","S2":"16"}},{"cols":4,"rows":5,"y":4,"x":5,SIZES:{"sizeName":"circle","S1":"33","S2":"43"}}];
let Obj2=[["bracket","4","2","3","2"],["square","3","2","0","2"],["circle","1","2","7","0"]];
const result = Obj1.map(item => {
const foundItem2 = Obj2.find(r => r[0] === item.SIZES.sizeName);
if(!foundItem2) return item;
const [, cols, rows, x, y] = foundItem2;
return {...item, cols, rows, x, y};
});
console.log(result);
Simple and savage way, easy to understand
const expected = Obj1.map((i) => {
const temp = Obj2.find((j) => j[0] === i.SIZES['sizeName']);
return temp
? { ...i, cols: temp[1], rows: temp[2], x: temp[3], y: temp[4] }
: i;
});
You can use lodash for this.
Here I am taking the name field in array2 as the id field.
finalArr = _(_.flatten([array1, array2]))
.groupBy('id')
.map(_.spread(_.assign))
.value();
This will work only if the array2 has id field with values of name field.
Both array must have a unique field so as to merge properly.
From what I understand, this would be my implementation using lodash:
var finalArray = _.zipWith(array1, array2, function(a,b){
return _.merge(a,b);
})
Check lodash docs here: https://lodash.com/docs/4.17.10