71

What do these three dots mean exactly, and why do I need them?

export function leadReducer(state: Lead[]= [], action: Action {
    switch(action.type){
        case ADD_LEAD:
            return [...state, action.payload];
        case REMOVE_LEAD:
            return state.filter(lead => lead.id !== action.payload.id )
}
}
David Klempfner
  • 8,700
  • 20
  • 73
  • 153
Anouar Mokhtari
  • 2,084
  • 4
  • 23
  • 23

4 Answers4

81

The three dots are known as the spread operator from Typescript (also from ES7).

The spread operator return all elements of an array. Like you would write each element separately:

let myArr = [1, 2, 3];
return [1, 2, 3];
//is the same as:
return [...myArr];

This is mostly just syntactic sugar as it compiles this:

func(...args);

to this:

func.apply(null, args);

In your case this gets compiled to this:

return [...state, action.payload];
//gets compiled to this:
return state.concat([action.payload]);
jakubde
  • 31
  • 1
  • 2
  • 4
Spitzbueb
  • 5,233
  • 1
  • 20
  • 38
  • I fail to see the difference between myArr, [1,2,3], [...myArr] – John Demetriou May 15 '20 at 12:58
  • @JohnDemetriou That's because it's the same. But `[myArr]` wouldn't be the same as `myArr`. The spread operator "spreads" the element of an array like arguments. `...[1, 2, 3]` results in `1, 2, 3`, which would, obviously, be the same if you put it in an array once more. – Spitzbueb May 17 '20 at 12:39
  • 1
    `a = [1, 2, 3]; b = (arr => [...arr])(a); c = (arr => arr)(a); a.push('a'); b.push('b'); c.push('c');` Just returning myArr (c) returns the same array, using the spread operator to create a new array (b) creates a separate object with the same contents. Since c is the same array instance as a, after this a and c are both [1,2,3,'a','c'] and b is [1,2,3,'b']. – Jason Goemaat May 18 '21 at 16:11
45

It is a spread operator (...) which is used for spreading the element of an array/object or for initializing an array or object from another array or object.

Let's create new array from existing array to understand this.

let Array1 = [ 1, 2, 3]; //1,2,3

let Array2 = [ 4, 5, 6]; //4,5,6

//Create new array from existing array

let copyArray = [...Array1]; //1,2,3

//Create array by merging two arrays

let mergedArray = [...Array1, ...Array2]; //1,2,3,4,5,6

//Create new array from existing array + more elements

let newArray = [...Array1, 7, 8]; //1,2,3,7,8

Shweta
  • 661
  • 6
  • 11
9

The ...(spread operator) works by returning each value from index 0 to index length-1:

Rahul Singh
  • 19,030
  • 11
  • 64
  • 86
1

Context: Take care of this particular behavior (by value / by reference) of the three dots spread syntax, when working with sub-arrays (or any other second level properties).

Finding: Take care that nested arrays (or sub-properties) are NOT passed by value, but by reference. In other words, only first level items are passed as a copy "by value". See the example:

sourceArray = [ 1, [2, 3] ] // Second element is a sub-array
targetArray = [ ...sourceArray]
console.log("Target array result:", JSON.stringify(targetArray), "\n\n") //it seems a copy, but...

console.log("Let's update the first source value:\n")
sourceArray[0] = 10
console.log("Updated source array:", JSON.stringify(sourceArray), "\n")
console.log("Target array is NOT updated, It keeps a copy by value:")
console.log(JSON.stringify(targetArray), "\n\n")

//But if you update a value of the sub-array, it has NOT been copied
console.log("Finally, let's update a nested source value:\n")
sourceArray[1][0] = 20
console.log("Updated source nested array:", JSON.stringify(sourceArray), "\n")
console.log("Target array is updated BY REFERENCE! ", )
console.log(JSON.stringify(targetArray), "\n\n") // it is not a copy, it is a reference!

console.log("CONCLUSION: ... spread syntax make a copy 'by value' for first level elements, but 'by reference' for second level elements (This applies also for objects) so take care!\n")
WalterAgile
  • 191
  • 1
  • 4