How to Clone an Object in TypeScript

  1. the Cloning Mechanisms in TypeScript
  2. Use the Spread Operator to Clone Objects in TypeScript
  3. Use the Object.assign() Method to Clone an Object in TypeScript
  4. Deep Copying of Nested Objects in TypeScript
  5. Deep Copy of Classes in TypeScript
How to Clone an Object in TypeScript

Cloning an object is a very common thing to do while implementing some services. Cloning refers to creating a copy of an existing object, including its fields.

Some use cases where the cloning of an object may come into use are returning a copy of an object in a function.

Changing some of its attributes or using setState in the case of React after changing some attributes. This article demonstrates different types of cloning mechanisms in TypeScript and how they can be implemented.

the Cloning Mechanisms in TypeScript

There are broadly two kinds of cloning mechanisms - shallow copy and deep copy. As its name suggests, a shallow copy copies the attributes and references nested attributes inside an object.

Meanwhile, in the case of deep copy, all its attributes are copied, and any change in the copied or cloned object does not affect the original object. The following code segment will discuss how shallow copy and deep copy works.

let a : number = 5;
let b = a;
b = 6;
//does not hold reference to previous original variable and thus is deep copied
console.log(b);
console.log(a);

type Person = {
    name : string;
    age : number;
}
var person : Person = {
    name : 'Geralt',
    age : 95
}
// shallow copy
var personCopy : Person = person;
personCopy.age = 90;
console.log(personCopy.age)
console.log(person.age)

Output:

6
5
90
90

Thus, implicit assigning only a shallow copy for an object as any change in the copied object affects the original object from which it was copied.

Use the Spread Operator to Clone Objects in TypeScript

The spread operator is a new addition to the features available in the JavaScript ES6 version and can make effective copies of an object. Considering the example in the previous code segment.

type Person = {
    name : string;
    age : number;
}
var person : Person = {
    name : 'Geralt',
    age : 95
}
var personCopy : Person = { ...person};
personCopy.age = 90;
console.log(personCopy.age)
console.log(person.age)

Output:

90
95

Thus the spread operator could make a deep copy of the object. However, it fails in the case of nested objects.

Use the Object.assign() Method to Clone an Object in TypeScript

The Object.assign() works similarly as in the case of the spread operator and can be used to clone simple objects, but it fails in the case of nested objects.

var personCopy : Person = Object.assign({}, person);

Deep Copying of Nested Objects in TypeScript

Every element must be copied recursively to copy nested objects. In the case of arrays, the spread operator works in the case of primitive data types.

However, every element has to be copied separately for an array of objects. We can design a function that achieves this;

function deepCopy<T>(instance : T) : T {
    if ( instance == null){
        return instance;
    }

    // handle Dates
    if (instance instanceof Date) {
        return new Date(instance.getTime()) as any;
    }

    // handle Array types
    if (instance instanceof Array){
        var cloneArr = [] as any[];
        (instance as any[]).forEach((value)  => {cloneArr.push(value)});
        // for nested objects
        return cloneArr.map((value: any) => deepCopy<any>(value)) as any;
    }
    // handle objects
    if (instance instanceof Object) {
        var copyInstance = { ...(instance as { [key: string]: any }
        ) } as { [key: string]: any };
        for (var attr in instance) {
            if ( (instance as Object).hasOwnProperty(attr)) 
                copyInstance[attr] = deepCopy<any>(instance[attr]);
        }
        return copyInstance as T;
    }
    // handling primitive data types
    return instance;
}
type info = {
    gender : 'male' | 'female';
}

type Person = {
    name : string;
    age : number;
    info : info;
}
var person : Person = {
    name : 'Geralt',
    age : 95,
    info : {
        gender : "male"
    }
}

var personCopy : Person = deepCopy<Person>(person);
console.log(personCopy);

personCopy.info.gender = "female";
console.log(person.info.gender);
console.log(personCopy,info.gender);

Output:

male
female

Thus successful deep copy is done for a nested object.

Deep Copy of Classes in TypeScript

Classes can be copied with a custom function and make a new instance inside that function. This gives the author complete control over the copy function.

class Witcher{
    name : string;
    age : number;
    constructor() {
        this.name = "Geralt"
        this.age  = 43;
    }
    greet(){
        return "Hi I am witcher known as " + this.name
    }

    copy(){
        var witcherIns = new Witcher();
        witcherIns.name = this.name;
        witcherIns.age = this.age;
        return witcherIns;
    }
}

var witcherObj = new Witcher();
var witcherObjCopy = witcherObj.copy();
console.log(witcherObjCopy);
console.log(witcherObjCopy.greet());

Output:

Witcher: {
  "name": "Geralt",
  "age": 43
} 
"Hi I am witcher known as Geralt" 
Shuvayan Ghosh Dastidar avatar Shuvayan Ghosh Dastidar avatar

Shuvayan is a professional software developer with an avid interest in all kinds of technology and programming languages. He loves all kinds of problem solving and writing about his experiences.

LinkedIn Website

Related Article - TypeScript Object