These problems are easier to think of in small steps, and I like using functional programming for processing data. First, let's extract the fruits and veggies from the rest.
const produce = data.filter(entry => ["fruit", "veg"].includes(entry.type));
const remainder = data.filter(entry => !["fruit", "veg"].includes(entry.type));
Technically we could have built both at once with forEach instead of calling filter twice, but I'd say clarity beats efficiency here.
Next we can merge the fruit and veg items with the .reduce function and clever use of the ... spread notation.
const mergedItems = produce.reduce((acc, entry) => [...acc, ...entry.items], []);
Finally, we can merge these all into an new object using the spread notation again:
const result = [
{ type: "veg", items: mergedItems },
...remainder
];
There you have it. Here's the result:
const data = [
{ type: 'fish', weight: '2kg' },
{ type: 'veg', items: ['carrot', 'cabbage', 'pea'] },
{ type: 'fruit', items: ['apple', 'pear', 'orange' ]}
];
const produce = data.filter(entry => ["fruit", "veg"].includes(entry.type));
const remainder = data.filter(entry => !["fruit", "veg"].includes(entry.type));
const mergedItems = produce.reduce((acc, entry) => [...acc, ...entry.items], []);
const result = [
{ type: "veg", items: mergedItems },
...remainder
];
console.log(result);
EDIT: Here are a few clarifications based on the comments.
Q: Is there away to keep a property from the original veg obj in the final result without hardcoding it?
If you don't mind modifying the original type="veg" entry, you could instead overwrite its items property only so that it includes fruits. But that question makes it sound like you know there's exactly one veg and one fruit entry, in which case the code above was complicated for nothing, and we could just use this:
const data = [
{ type: 'fish', weight: '2kg' },
{ type: 'veg', price: "3.00", items: ['carrot', 'cabbage', 'pea'] },
{ type: 'fruit', items: ['apple', 'pear', 'orange' ]}
];
const vegEntry = data.find(entry => entry.type === "veg");
const fruitIndex = data.findIndex(entry => entry.type === "fruit");
vegEntry.items = [...vegEntry.items, ...data[fruitIndex].items];
data.splice(fruitIndex, 1);
console.log(data);
This adds the fruit items to the veg entry items and removes the fruit entry, therefore preserving all the properties of the veg entry.
If for some reason you don't want to modify the data in place and would rather create a new result object, you would change it to:
const data = [
{ type: 'fish', weight: '2kg' },
{ type: 'veg', price: "3.00", items: ['carrot', 'cabbage', 'pea'] },
{ type: 'fruit', items: ['apple', 'pear', 'orange' ]}
];
const vegIndex = data.findIndex(entry => entry.type === "veg");
const fruitIndex = data.findIndex(entry => entry.type === "fruit");
const newVegEntry = {...data[vegIndex]};
newVegEntry.items = [...newVegEntry.items, ...data[fruitIndex].items];
const result = [...data];
result[vegIndex] = newVegEntry;
result.splice(fruitIndex, 1);
console.log(result);
If this doesn't work in your browser it might be due to the {...data[vegIndex]} syntax which is a bit more modern. You might want to use Object.assign({}, data[vegIndex]} instead to create a shallow copy of the veg entry.