381 Stimmen

Typescript - Objekt klonen

Ich habe eine Superklasse, die das Elternelement (Entity) für viele Unterklassen (Customer, Product, ProductCategory...) ist

Ich möchte in Typescript dynamisch ein Objekt klonen, das verschiedene Teilobjekte enthält.

Zum Beispiel: ein Customer, der verschiedene Product enthält, die eine ProductCategory haben

var cust:Customer = new Customer();

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

Um den gesamten Objektbaum zu klonen, habe ich eine Funktion in Entity erstellt

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

Der new Fehler tritt auf, wenn er zu Javascript transpiliert wird: Fehler TS2351: Kann 'new' nicht mit einem Ausdruck verwenden, dessen Typ über eine Aufruf- oder Konstruktions-Signatur verfügt.

Obwohl das Skript funktioniert, möchte ich den transpilierten Fehler loswerden

19voto

Homer Punkte 7346

Es ist einfach, eine oberflächliche Kopie mit "Object Spread" in TypeScript 2.1 zu erhalten

dieser TypeScript: let copy = { ...original };

erzeugt dieses 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

14voto

Hier ist die deepCopy-Implementierung in TypeScript (kein any ist im Code enthalten):

const deepCopy =  ? 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((o, prop) => {
      Object.defineProperty(o, prop, Object.getOwnPropertyDescriptor(source, prop)!)
      o[prop] = deepCopy(source[prop])
      return o
    }, Object.create(Object.getPrototypeOf(source)))
  }
  return source
}

12voto

user2878850 Punkte 2246

Fügen Sie "lodash.clonedeep": "^4.5.0" zu Ihrer package.json hinzu. Verwenden Sie es dann wie folgt:

import * as _ from 'lodash';

...

const copy = _.cloneDeep(original)

9voto

Wenn Sie auch die Methoden kopieren möchten und nicht nur die Daten, befolgen Sie diesen Ansatz

let copy = new BaseLayer() ;
Object.assign(copy, origin);
copy.x = 8 ; // wird das Ursprungsobjekt nicht beeinflussen

Ändern Sie einfach BaseLayer in den Namen Ihrer Klasse.

8voto

Muhammad Ali Punkte 600

Meine Meinung dazu:

Object.assign(...) kopiert nur Eigenschaften und wir verlieren das Prototyp und Methoden.

Object.create(...) kopiert keine Eigenschaften für mich und erzeugt nur einen Prototypen.

Was für mich funktioniert hat, ist die Erstellung eines Prototyps mit Object.create(...) und das Kopieren von Eigenschaften darauf mit Object.assign(...):

Also für ein Objekt foo mache den Klon so:

Object.assign(Object.create(foo), foo)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X