我有一个超类,它是许多子类(Customer, Product, ProductCategory…)的父类(Entity)。

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

例如:拥有不同产品的客户拥有一个ProductCategory

var cust:Customer  = new Customer ();

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

为了克隆对象的整个树,我在实体中创建了一个函数

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时,将引发以下错误:错误TS2351:不能对缺少调用或构造签名的表达式使用'new'。

虽然脚本工作,但我想摆脱转译错误


当前回答

@fenton对选项4的补充,使用angularJS,使用以下代码对对象或数组进行深度复制是相当简单的:

var deepCopy = angular.copy(objectOrArrayToBeCopied)

更多文档可以在这里找到:https://docs.angularjs.org/api/ng/function/angular.copy

其他回答

我自己也遇到过这个问题,最后写了一个小库clone -ts,它提供了一个抽象类,它向任何扩展它的类添加了一个克隆方法。抽象类借用了芬顿接受的答案中描述的深度复制函数,只是替换了Copy = {};使用copy = object. create(originalObj)来保留原始对象的类。下面是一个使用该类的示例。

import {Cloneable, CloneableArgs} from 'cloneable-ts';

// Interface that will be used as named arguments to initialize and clone an object
interface PersonArgs {
    readonly name: string;
    readonly age: number;
}

// Cloneable abstract class initializes the object with super method and adds the clone method
// CloneableArgs interface ensures that all properties defined in the argument interface are defined in class
class Person extends Cloneable<TestArgs>  implements CloneableArgs<PersonArgs> {
    readonly name: string;
    readonly age: number;

    constructor(args: TestArgs) {
        super(args);
    }
}

const a = new Person({name: 'Alice', age: 28});
const b = a.clone({name: 'Bob'})
a.name // Alice
b.name // Bob
b.age // 28

或者你可以直接用克隆。克隆助手方法:

import {Cloneable} from 'cloneable-ts';

interface Person {
    readonly name: string;
    readonly age: number;
}

const a: Person = {name: 'Alice', age: 28};
const b = Cloneable.clone(a, {name: 'Bob'})
a.name // Alice
b.name // Bob
b.age // 28    

通过在TypeScript 2.1中引入的“Object Spread”,很容易获得一个浅拷贝

this TypeScript: let copy ={…原始};

生成这个JavaScript:

var __assign = (this && this.__assign) || Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
        s = arguments[i];
        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
            t[p] = s[p];
    }
    return t;
};
var copy = __assign({}, original);

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html

如果你得到这个错误:

TypeError: this.constructor(...) is not a function

这是正确的脚本:

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

最后我这样做了:

public clone(): any {
  const result = new (<any>this.constructor);

  // some deserialization code I hade in place already...
  // which deep copies all serialized properties of the
  // object graph
  // result.deserialize(this)

  // you could use any of the usggestions in the other answers to
  // copy over all the desired fields / properties

  return result;
}

因为:

var cloneObj = new (<any>this.constructor());

@Fenton给出了运行时错误。

Typescript版本:2.4.2

添加“lodash。Clonedeep ": "^4.5.0"到你的package.json。然后像这样使用:

import * as _ from 'lodash';

...

const copy = _.cloneDeep(original)