打字稿 \- 克隆对象

新手上路,请多包涵

I have a super class that is the parent ( Entity ) for many subclass ( Customer , Product , ProductCategory …)

我正在寻找动态克隆一个包含 Typescript 中不同子对象的对象。

例如: Customer 有不同的 Product 谁有 ProductCategory

 var cust:Customer  = new Customer ();

cust.name = "someName";
cust.products.push(new Product(someId1));
cust.products.push(new Product(someId2));

为了克隆整个对象树,我在 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;
}

new 转译为 javascript 时出现以下错误: error TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.

虽然脚本有效, 但我想摆脱编译错误

原文由 David Laberge 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 558
2 个回答

解决具体问题

您可以使用类型断言告诉编译器您更了解:

 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;
}

克隆

截至 2022 年,有一项提议允许 structuredClone 深度复制许多类型。

 const copy = structuredClone(value)

你可以在什么样的东西上使用 它有一些限制。

请记住,有时最好编写自己的映射 - 而不是完全动态的。但是,您可以使用一些“克隆”技巧来获得不同的效果。

我将在所有后续示例中使用以下代码:

 class Example {
  constructor(public type: string) {

  }
}

class Customer {
  constructor(public name: string, public example: Example) {

  }

  greet() {
    return 'Hello ' + this.name;
  }
}

var customer = new Customer('David', new Example('DavidType'));


选项 1:传播

属性: 是的

方法:没有

深拷贝:否

var clone = { ...customer };

alert(clone.name + ' ' + clone.example.type); // David DavidType
//alert(clone.greet()); // Not OK

clone.name = 'Steve';
clone.example.type = 'SteveType';

alert(customer.name + ' ' + customer.example.type); // David SteveType


选项 2:Object.assign

属性: 是的

方法:没有

深拷贝:否

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

alert(clone.name + ' ' + clone.example.type); // David DavidType
alert(clone.greet()); // Not OK, although compiler won't spot it

clone.name = 'Steve';
clone.example.type = 'SteveType';

alert(customer.name + ' ' + customer.example.type); // David SteveType


选项 3:Object.create

属性: 继承

方法: 继承

Deep Copy: Shallow Inherited (深度更改影响原始和克隆)

 var clone = Object.create(customer);

alert(clone.name + ' ' + clone.example.type); // David DavidType
alert(clone.greet()); // OK

customer.name = 'Misha';
customer.example = new Example("MishaType");

// clone sees changes to original
alert(clone.name + ' ' + clone.example.type); // Misha MishaType

clone.name = 'Steve';
clone.example.type = 'SteveType';

// original sees changes to clone
alert(customer.name + ' ' + customer.example.type); // Misha SteveType


选项 4:深度复制功能

属性: 是的

方法:没有

深拷贝:

function deepCopy(obj) {
    var copy;

    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = deepCopy(obj[i]);
        }
        return copy;
    }

    // Handle Object
    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.");
}

var clone = deepCopy(customer) as Customer;

alert(clone.name + ' ' + clone.example.type); // David DavidType
// alert(clone.greet()); // Not OK - not really a customer

clone.name = 'Steve';
clone.example.type = 'SteveType';

alert(customer.name + ' ' + customer.example.type); // David DavidType

原文由 Fenton 发布,翻译遵循 CC BY-SA 4.0 许可协议

这是 deepCopy 在 TypeScript 中的实现(代码中不包含 any ):

 const deepCopy = <T, U = T extends Array<infer V> ? V : never>(source: T ): T => {
  if (Array.isArray(source)) {
    return source.map(item => (deepCopy(item))) as T & U[]
  }
  if (source instanceof Date) {
    return new Date(source.getTime()) as T & Date
  }
  if (source && typeof source === 'object') {
    return (Object.getOwnPropertyNames(source) as (keyof T)[]).reduce<T>((o, prop) => {
      Object.defineProperty(o, prop, Object.getOwnPropertyDescriptor(source, prop)!)
      o[prop] = deepCopy(source[prop])
      return o
    }, Object.create(Object.getPrototypeOf(source)))
  }
  return source
}

原文由 Sandro Skhirtladze 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题