2015-12-10 15 views
7

Ho bisogno di clonare in profondità un oggetto in TypeScript. Questo non dovrebbe essere un problema in quanto librerie come Lodash forniscono funzioni appropriate per questo. Tuttavia, questi sembrano scartare le informazioni sul tipo.Deep clone in TypeScript (tipi di conservazione)

> var a = new SomeClass(); 
> a instanceof SomeClass; 
< true 
> var b = _.cloneDeep(a); 
> b instanceof SomeClass; 
< false 

C'è un modo per clonare gli oggetti in TypeScript preservando queste informazioni di digitazione?

+0

qualcosa come 'b: typeof a'? – YOU

+4

Automaticamente? No. Dovresti implementare un metodo clone sull'oggetto e sui suoi oggetti nidificati. –

+0

La conservazione dei tipi di dattiloscritto e la conservazione di SomeClass.prototype non sono la stessa cosa. Vedi @Retsam answer e https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof. I tipi di dattiloscritto vengono cancellati in fase di runtime. –

risposta

4

C'è un post interessante sulla clonazione profonda http://blog.soulserv.net/understanding-object-cloning-in-javascript-part-ii/. È possibile usare l'esecuzione dell'autore della funzione profonda clonazione clone():

class SomeClass { 
    constructor(public test) { 

    } 
} 

let c = new SomeClass("Hey!"); 
c.test = "Hey!"; 

console.log(c instanceof SomeClass); // returns true 

let cloneC = clone(c, /* resolve circular references */ true); 

console.log(cloneC instanceof SomeClass); // returns true 

[clone() source code] [Complete source code]

6

tipografico non è scartando le informazioni sul tipo qui. Nel file DefinitelyTyped lodash.d.ts, si può vedere che cloneDeep è definito come

cloneDeep<T>(
    val: T, 
    customizer?: (value: any) => any, 
    thisArg?: any 
) : T 

Ignorando gli argomenti che non si preoccupano, ci vuole un T come input, e sputa fuori un T come output. Quindi Typescript non sta perdendo alcun tipo di informazione; considera l'output di cloneDeep lo stesso tipo dell'input.

Dovresti essere in grado di verificarlo tramite il tuo editor: assumendo che tu abbia un editor che ti permetta di ispezionare il tipo di variabili o metodi di autocompletes (che consiglio vivamente, se non lo fai).


Perché allora lo typeof non funziona come previsto? È perché le informazioni sul tipo Typescript non vengono trasferite in runtime. instanceof è un operatore nativo JS, che tipografico non modifica il comportamento di, che potete vedere eseguendo questo frammento:

"use strict"; 
 
class A {} 
 

 
let a = new A(); 
 
let b = _.cloneDeep(a); 
 

 
if (b instanceof A) { 
 
    alert("b is an instance of A"); 
 
} else { 
 
    alert("b is not an instance of A"); 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>

La ragione per cui b instanceof A è falso è che instanceof sta controllando contro i costruttori: x instanceof A restituisce true se la funzione A è un costruttore da qualche parte nella catena di prototipi di x (consultare la documentazione MDN su instanceof). Lodash, tuttavia, non usa i costruttori quando clona oggetti. Non può (Come saprebbe quali argomenti passare?) Crea un oggetto JS semplice che ha tutti i metodi dell'oggetto clonato, ma non riproduce la catena del prototipo.

Lodash clone (e la maggior parte dei metodi di lodash, in realtà) è il modo migliore di utilizzare oggetti JS non elaborati. Se la stai usando in combinazione con i costruttori e instanceof, le cose si fanno un po 'torbide.


Una soluzione è quella di evitare il controllo instanceof, e fare qualcosa di simile a tipizzazione anatra; non controllare che il costruttore dell'oggetto sia una funzione particolare, ma controlla che l'oggetto abbia le proprietà che ti aspetti.

Un'altra soluzione è, come suggerito nei commenti, implementare un metodo clone sulla classe stessa, che non userebbe lodash.

1

È possibile utilizzare l'utilità Lodash#cloneDeep. Esempio di utilizzo:

import * as _ from "lodash"; 

... 

{ 
    this.cloned = _.cloneDeep(data); 
}