How to merge Objects in TypeScript

avatar

Borislav Hadzhiev

Last updated: Feb 20, 2022

banner

Photo from Unsplash

Merging Objects in TypeScript #

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.

index.ts
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.

Notice that even though we haven't explicitly added types to any of the objects, TypeScript is able to infer the type.

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.

index.ts
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.

index.ts
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.

index.ts
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.

index.ts
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.

Intersection types are defined using an ampersand & 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.

index.ts
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.

index.ts
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.

index.ts
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 (...).

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.