The spread operator in TypeScript is a powerful feature that allows you to easily expand the contents of an array or object. This can come in handy when you need to make a copy of an existing object or array, or when you want to merge multiple arrays or objects together.

What is the spread operator?

The spread operator (…) expands any iterable object into a list of arguments. This mainly means things like arrays and objects.

For example:

const myArr = [1, 2, 3];
console.log('Array');
printArgs(myArr);
console.log('Spread');
printArgs(...myArr);

Here’s the result:

In the first case, we get just the one array as an argument, but in the second case, each value in the array gets provided as an argument separately.

Why is this useful?

Firstly, this means that anywhere that is expecting a list of arguments and you have an array, you can use the spread operator to transform your array.

This is especially useful in TypeScript’s Math functions, which expect separate arguments rather than numbers:

const myArr = [1, 2, 3, 4, 5];
Math.max(myArr); //❌ TS2345: Argument of type 'number[]' is not assignable to parameter of type 'number'.
Math.max(...myArr); //✔ 5 ️

Copying Objects/Arrays

If we take a look at the object {} and array [] syntax, these essentially accept a list of arguments as well. You might have created a new array by doing something like:

const myarr = [1,2,3];

Which looks very similar to:

const myArr = new Array(1,2,3); //1,2,3 are arguments!

This means we can copy an object/array by turning it into a list of arguments, and then putting those arguments into a new object/array.

Arrays

Here’s how you use the spread operator to clone an array:

const users = ['adam', 'brian', 'carl'];
const newUsers = [...users];

newUsers.pop();

console.log(newUsers); //adam, brian
console.log(users); //adam, brian, carl

Objects

The syntax is very similar for objects:

const myObject = { foo: 'bar' };
const myNewObject = { ...myObject };

Shallow Clones

One important thing to note here is that we’re creating shallow copies. Let’s explore what that means through an example:

const adam = { money: 10 };
const brian = { money: 20 };

const usersObject = { adam, brian };
const newUsersObject = { ...usersObject };

I’ve just created a simple object, and we’re cloning it with the spread operator. Now let’s perform some actions on it:

newUsersObject.adam.money = 100;
newUsersObject['adam'] = { money: 200 };

In the clone, Adam’s money is 200, just because that’s what we’ve set it to last. So what should Adam’s money be set to in the original, 10, 100 or 200? You might expect the original should still be 10, since we cloned the array, but let’s have a look:

Why has Adam changed, even though we’ve cloned the object? This is because we’ve created a shallow clone. usersObject and newUsersObject refer to two different objects, but every object in them still refers to the same object. usersObject.adam is the same object as newUsersObject.adam.

In the first operation, this means we’re modifying the same object. In the second operation, since we’re actually changing what newUsersObject.adam refers to, nothing happens with the original.

Merging Objects/Arrays

You can also use the spread operator to merge two objects/arrays together. The syntax is essentially identical to cloning.

For arrays:

const firstNumbers = [1, 2, 3];
const nextNumbers = [4, 5, 6];
const fullNumbers = [...firstNumbers, ...nextNumbers]; //[1,2,3,4,5,6]

For objects:

const foo = { foo: 'foo' };
const bar = { bar: 'bar' };
const foobar = { ...foo, ...bar }; //{ foo: 'foo', bar: 'bar'}

Adding to objects/arrays

Adding an item to an object/array looks very similar to cloning.

For arrays:

const middleNumbers  = [4,5,6];
const fullNumbers = [1,2,3, ...middleNumbers, 4,5,6]; //1,2,3,4,5,6,7,8,9

You can add an item anywhere around the array, and you can add any number of items.

It works very similarly for objects:

const foo = { foo: 'foo' };
const foobar = { ...foo, bar: 'bar' }; //{ foo: 'foo', bar: 'bar'}

But why?

For cloning, adding items, merging, etc, you might wonder why you would use the spread operator over solutions like .push(), or just setting a property. The main benefit in a lot of cases is mutability.

In a lot of cases, such as when building apps with React, you may not want to modify the original array/object directly. In some cases this is fine, concat() for example does not modify the original array, but in other cases such as when pushing and popping from an array, these will modify it, whereas using spread will give you a new array.

Conclusion

That’s all! Thanks for reading this article, hopefully, you now understand how and when to use the spread operator in TypeScript. If you liked this article, feel free to leave a comment below!

Avatar photo
👋 Hey, I'm Omari Thompson-Edwards
Hey, I'm Omari! I'm a full-stack developer from the UK. I'm currently looking for graduate and freelance software engineering roles, so if you liked this article, reach out on Twitter at @marile0n

💬 Leave a comment

Your email address will not be published. Required fields are marked *

We will never share your email with anyone else.