Loop over objects inside a list and return unique values

Make two sets instead, one for the options found so far, and one for the types found so far:

const obj = {
  "products": [{
    "id": 1,
    "tags": {
      "option": ["A", "B"]
    }
  }, {
    "id": 2,
    "tags": {
      "option": ["B"],
      "type": ["A", "B", "C"]
    }
  }, {
    "id": 3,
    "tags": {
      "type": ["A"]
    }
  }, {
    "id": 4,
    "tags": {
      "option": ["B", "C"],
      "type": ["A", "C"]
    }
  }]
};
const options = new Set();
const types = new Set();
for (const { tags: { option=[], type=[] } } of obj.products) {
  for (const o of option) options.add(o);
  for (const t of type) types.add(t);
}
console.log({
  option: [...options],
  type: [...types]
});

An alternative, for arbitrary keys:

const obj = {
  "products": [{
    "id": 1,
    "tags": {
      "option": ["A", "B"]
    }
  }, {
    "id": 2,
    "tags": {
      "option": ["B"],
      "type": ["A", "B", "C"]
    }
  }, {
    "id": 3,
    "tags": {
      "type": ["A"]
    }
  }, {
    "id": 4,
    "tags": {
      "option": ["B", "C"],
      "type": ["A", "C"]
    }
  }]
};
const setObj = {};
for (const { tags } of obj.products) {
  for (const [key, arr] of Object.entries(tags)) {
    if (!setObj[key]) setObj[key] = new Set();
    for (const item of arr) setObj[key].add(item);
  }
}
const output = Object.fromEntries(
  Object.entries(setObj).map(([key, set]) => [key, [...set]])
);
console.log(output);


You could take a Map for wanted keys and collect the values in a Set.

function getUnique(array, keys) {
    var maps = new Map(keys.map(k => [k, new Set]));

    array.forEach(({ tags }) =>
        keys.forEach(k => (tags[k] || []).forEach(v => maps.get(k).add(v))));

    return Array.from(maps, ([k, s]) => ({ [k]: Array.from(s) }));
}

var data = { products: [{ id: 1, tags: { option: ["A", "B"] } }, { id: 2, tags: { option: ["B"], type: ["A", "B", "C"] } }, { id: 3, tags: { type: ["A"] } }, { id: 4, tags: { option: ["B", "C"], type: ["A", "C"] } }] },
    unique = getUnique(data.products, ['option', 'type']);

console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }


You can create an object with two required keys and then set then to empty arrays. Then loop through the array and add the new elements to that array and after that remove the duplicates

const arr = [{
"id": 1,
"tags": {
  "option": ["A", "B"]
}}, {
"id": 2,
"tags": {
  "option": ["B"],
  "type": ["A", "B", "C"]
} }, {
"id": 3,
"tags": {
  "type": ["A"]
}}, {
"id": 4,
"tags": {
  "option": ["B", "C"],
  "type": ["A", "C"]
}}]

const object = {option:[] , type: []}
arr.forEach(({tags}) => {
  for(let prop in object){
    if(tags[prop]){
      object[prop] = [...new Set([...object[prop], ...tags[prop]])]
    }
  }
  
})
console.log(object)