RxJS : how to understand the spread operator here?

Viewed 76

I have this code as an example :

 productsWithCategory$ = combineLatest([
    this.products$,
    this.productCategoryService.productCategories$
  ]).pipe(
    map(([products, categories]) =>
      products.map(product => ({
        ...product,
        price: product.price ? product.price * 1.5 : 0,
        category: categories.find(c => product.categoryId === c.id)?.name,
        searchKey: [product.productName]
      } as Product))
    ),
    shareReplay(1)
  );

I want to know how this part works with the spread operator ... ?

  products.map(product => ({
    ...product,
    price: product.price ? product.price * 1.5 : 0,
    category: categories.find(c => product.categoryId === c.id)?.name,
    searchKey: [product.productName]
  } as Product)

as far as I understand the operator ... will copy the old object properties to a new object, but why when we add price again it still works ? doesn't it mean that now we have 2 properties "price" in that object ?

3 Answers

The already existent object properties will not be repeated (just updated). The new ones will be created. A minimal reproducible example that shows this behavior is:

products = [{key1: 4.2, key2: "blabla"}, {key1: 3.1, key2: "blibli"}]


products = products.map(product => ({
    ...product,
    key1: 1.0,
    key2: "bloblo",
    key3: "lalala"
}))

console.log(products);

Output

[
  { key1: 1, key2: 'bloblo', key3: 'lalala' },
  { key1: 1, key2: 'bloblo', key3: 'lalala' }
]

Notice that key1 and key2 (already existent properties) aren't repeated (just updated).

key3 (not existent before), is created.

From what I understand the spread operator works both to add new keys to an object and to overwrite the keys it already has.

I imagine a product object like this:

product = {
  price: 0,
  category: a
};

Now we copy the object with the spread operator:

const product2 = {...product};

Now you have another object (in another memory location) with the same content as product.

Now we create a new object with other values with the spread operator:

const produc3 = { ...product, price: 1, category: b };

Now you have an object that has the same keys as the original but with other values.

Now we add a new key to the object:

const product4 =  { ...product, name: 'car'};

Now you have an object that has the same keys as the original object, plus the name key.

You will never have an object with 2 keys the same. enter image description here

Tested in the chrome console, if you try to define an object with two equal keys only the last key of the definition prevails.

It is a JavaScript feature not RxJS specific per say. I think this snippet of code (or similar) is part of RxJS examples slides of Deborah Kurata conference or something like this. If you are interested, there is a record on youtube on a similar usage of this syntax with RxJS by Deborah Kurata. As mentioned on MDN:

Spread syntax can be used when all elements from an object or array need to be included in a new array or object, or should be applied one-by-one in a function call's arguments list. There are three distinct places that accept the spread syntax:

Function arguments list (myFunction(a, ...iterableObj, b))

Array literals ([1, ...iterableObj, '4', 'five', 6])

Object literals ({ ...obj, key: 'value' })

In our case above it is called shallow cloning with Object literals. Read more here

Related