Comprehensive Analysis of Object Cloning in TypeScript: Implementation Strategies from Shallow to Deep Copy

Nov 05, 2025 · Programming · 31 views · 7.8

Keywords: TypeScript | Object Cloning | Deep Copy | Shallow Copy | Type Assertion

Abstract: This article provides an in-depth exploration of various object cloning methods in TypeScript, focusing on resolving type errors when dynamically cloning object trees. By analyzing the type assertion solution from the best answer, it systematically compares the advantages and disadvantages of spread operator, Object.assign, Object.create, and custom deep copy functions. Combined with modern JavaScript's structuredClone API, it offers complete cloning solutions covering key issues such as prototype chain handling, method inheritance, and circular references, providing practical technical guidance for developers.

Problem Background and Core Challenges

In TypeScript object-oriented programming, there is often a need to clone object trees containing complex nested structures. As shown in the Q&A data, developers face a typical scenario: the Customer class contains multiple Product objects, and each Product is associated with a ProductCategory. This multi-level nested relationship makes simple assignment operations insufficient, as they maintain object references, causing modifications to cloned objects to affect the original objects.

Analysis of Original Cloning Solution Issues

The developer initially implemented a recursive cloning method in the base class Entity:

public clone(): any {
    var cloneObj = new this.constructor();
    for (var attribut in this) {
        if(typeof this[attribut] === "object"){
           cloneObj[attribut] = this.clone();
        } else {
           cloneObj[attribut] = this[attribut];
        }
    }
    return cloneObj;
}

This solution is logically correct but generates an error during TypeScript compilation: error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.. This occurs because TypeScript's type system cannot determine the specific type of this.constructor at compile time.

Type Assertion Solution

The best answer provides a method to eliminate compilation errors using type assertion:

public clone(): any {
    var cloneObj = new (this.constructor() as any);
    for (var attribut in this) {
        if (typeof this[attribut] === "object") {
            cloneObj[attribut] = this[attribut].clone();
        } else {
            cloneObj[attribut] = this[attribut];
        }
    }
    return cloneObj;
}

Through the as any type assertion, the compiler is explicitly instructed to skip type checking for this.constructor. This method maintains the logical integrity of recursive cloning while resolving compilation errors.

Modern Cloning API: structuredClone

With the evolution of web standards, modern browsers provide the structuredClone API for deep cloning:

const copy = structuredClone(value)

This API supports most JavaScript built-in types, including Array, Object, Map, Set, etc., but has some limitations: it cannot clone functions, DOM nodes, prototype chains, etc. For complex custom class instances, custom cloning methods are still required.

Shallow Copy Method Comparison

For scenarios that do not require deep cloning, TypeScript offers multiple shallow copy options:

Spread Operator

var clone = { ...customer };

Advantages: Concise syntax, directly copies enumerable properties. Disadvantages: Does not copy methods, does not handle nested objects.

Object.assign Method

var clone = Object.assign({}, customer);

According to Reference Article 1, Object.assign copies all enumerable own properties to the target object. If the source value is an object reference, only the reference value is copied, not the object itself.

Object.create Method

var clone = Object.create(customer);

Creates a new object based on prototype inheritance, sharing methods and properties. Modifying prototype properties affects all instances, making it unsuitable for scenarios requiring independent copies.

Deep Copy Implementation Strategies

For scenarios requiring completely independent copies, deep copy must be implemented:

Recursive Deep Copy Function

function deepCopy(obj) {
    var copy;
    
    if (null == obj || "object" != typeof obj) return obj;
    
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }
    
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = deepCopy(obj[i]);
        }
        return copy;
    }
    
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = deepCopy(obj[attr]);
        }
        return copy;
    }
    
    throw new Error("Unable to copy obj! Its type isn't supported.");
}

JSON Serialization Method

Reference Article 2 mentions using JSON.stringify and JSON.parse to achieve deep cloning:

let customUser2 = JSON.parse(JSON.stringify(user2))

This method is simple and effective but has significant limitations: it cannot handle functions, undefined, circular references, and other special cases.

Performance and Applicable Scenario Analysis

Shallow copy operations offer optimal performance and are suitable for flat data structures or scenarios that do not require completely independent copies. Deep copy consumes more resources but ensures complete data independence. In actual development, appropriate cloning strategies should be selected based on specific requirements.

Best Practice Recommendations

1. For simple data structures, prioritize using the spread operator or Object.assign

2. When deep cloning is needed, consider using the structuredClone API (if the environment supports it)

3. For cloning custom class instances, it is recommended to implement the clone method in the base class, using type assertions to resolve compilation issues

4. Avoid using JSON serialization methods in scenarios containing functions or special objects

5. In performance-sensitive scenarios, evaluate whether true deep cloning is necessary, or whether deep cloning requirements can be avoided through data structure design

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.