Borislav Hadzhiev
Sun Feb 20 2022·3 min read
Photo by Elijah Hail
Use the spread syntax (...) to merge objects in TypeScript, e.g.
const obj3 = { ...obj1, ...obj2 }
. The type of the final object will
successfully be inferred, so trying to add or remove properties from it will
cause the type checker to show an error.
const obj1 = { name: 'Tom', age: 30 }; const obj2 = { country: 'Chile' }; // 👇️ const obj3: {country: string; name: string; age: number;} const obj3 = { ...obj1, ...obj2 }; console.log(obj3); // 👉️ {name: 'Tom', age: 30, country: 'Chile'}
We used the spread syntax (...) to unpack the properties from 2 objects into a third.
For example, if I try to add a new key-value pair to obj3
or try to delete a
key from the object, TypeScript will show an error.
const obj1 = { name: 'Tom', age: 30 }; const obj2 = { country: 'Chile' }; // 👇️ const obj3: {country: string; name: string; age: number;} const obj3 = { ...obj1, ...obj2 }; console.log(obj3); // 👉️ {name: 'Tom', age: 30, country: 'Chile'} // ⛔️ Error: Property 'test' does not exist // on type '{ country: string; name: string; age: number; }'. obj3.test = 'hello'; // ⛔️ Error: The operand of a 'delete' operator must be optional. delete obj3['name'];
The type checker shows an error, because the final object is already typed to
have the country
, name
and age
properties set to specific types.
However, you are able to update properties that exist on the object, as long as you provide a value that is the correct type.
const obj1 = { name: 'Tom', age: 30 }; const obj2 = { country: 'Chile' }; // 👇️ const obj3: {country: string; name: string; age: number;} const obj3 = { ...obj1, ...obj2 }; console.log(obj3); // 👉️ {name: 'Tom', age: 30, country: 'Chile'} obj3.name = 'Alice'; obj3.age = 29; console.log(obj3); // 👉️ {name: 'Alice', age: 29, country: 'Chile'}
When merging objects, the order is important, because if two objects have the same key, the object whose properties are unpacked later wins.
const obj1 = { name: 'Tom', age: 30 }; const obj2 = { name: 'Alice' }; // 👇️ const obj3: {name: string; age: number} const obj3 = { ...obj1, ...obj2 }; console.log(obj3); // 👉️ {name: 'Alice', age: 30}
Both of the objects have the name
property, however the keys of obj2
are
unpacked later, so its value overrides the value of the name
property in
obj1
.
You might also see the Object.assign()
method being used to merge objects in
TypeScript.
const obj1 = { name: 'Tom', age: 30 }; const obj2 = { country: 'Chile' }; // 👇️ const obj3: {name: string; age: number} & {country: string} const obj3 = Object.assign({}, obj1, obj2); console.log(obj3); // 👉️ {name: 'Tom', age: 30, country: 'Chile'}
The first parameter the
Object.assign
method takes is the target
object - the object to which the properties of the
source objects are applied.
The next parameters the method takes are one or more source objects.
TypeScript is also able to infer the type of the new object using an intersection type.
&
and are used to combine existing object types. You can use the &
operator as many times as necessary to construct a type.If you try to add a new property to the object or delete an existing property, the type checker will throw an exception.
const obj1 = { name: 'Tom', age: 30 }; const obj2 = { country: 'Chile' }; // 👇️ const obj3: {name: string; age: number} & {country: string} const obj3 = Object.assign({}, obj1, obj2); console.log(obj3); // 👉️ {name: 'Tom', age: 30, country: 'Chile'} // ⛔️ Error: Property 'test' does not exist // on type '{ country: string; name: string; age: number; }'. obj3.test = 'hello'; // ⛔️ Error: The operand of a 'delete' operator must be optional. delete obj3['name'];
This works in the same way as using the spread syntax (...).
You are still able to update existing properties of the object, as long as you provide a value of the correct type.
const obj1 = { name: 'Tom', age: 30 }; const obj2 = { country: 'Chile' }; // 👇️ const obj3: {name: string; age: number} & {country: string} const obj3 = Object.assign({}, obj1, obj2); console.log(obj3); // 👉️ {name: 'Tom', age: 30, country: 'Chile'} obj3.name = 'Alice'; console.log(obj3); // 👉️ {name: 'Alice', age: 30, country: 'Chile'}
The properties of the target object are overwritten by other objects that have the same properties later in the parameter order.
const obj1 = { name: 'Tom', age: 30 }; const obj2 = { name: 'Alice' }; // 👇️ const obj3: {name: string; age: number} & {country: string} const obj3 = Object.assign({}, obj1, obj2); console.log(obj3); // 👉️ {name: 'Alice', age: 30}
This behavior is also consistent with the spread syntax (...).