繁体   English   中英

TypeScript中的深度克隆(保留类型)

[英]Deep clone in TypeScript (preserving types)

我需要在TypeScript中深度克隆一个对象。 这应该不是问题,因为像Lodash这样的库提供了适当的功能。 但是,这些似乎丢弃了类型信息。

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

有没有办法在保留此类型信息的同时克隆TypeScript中的对象?

打字稿不会丢弃类型信息。 在DefinitelyTyped lodash.d.ts文件中,您可以看到cloneDeep被定义为

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

忽略我们不关心的参数,它需要一个T作为输入,并吐出一个T作为输出。 因此,Typescript不会丢失任何类型的信息; 它认为cloneDeep的输出与输入的类型相同。

您应该能够通过编辑器验证这一点:假设您有一些编辑器可以让您检查变量的类型或自动填充方法(如果您不这样做,我强烈建议您这样做)。


为什么typeof不能像你期望的那样工作? 这是因为Typescript类型信息不会延续到运行时。 instanceof是一个本机JS运算符,其中的Typescript不会改变其行为,您可以通过运行此代码段来查看:

 "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> 

b instanceof A为false的原因是instanceof正在检查构造函数:如果函数A是x的原型链中的某个构造函数Ax instanceof A返回true(请参阅instanceof上的MDN文档)。 但是,Lodash在克隆对象时不使用构造函数。 它不能。 (它如何知道要传递的参数?)它创建了一个普通的JS对象,它具有克隆对象的所有方法,但不会重现它的原型链。

在处理原始JS对象时,最好使用Lodash的clone (以及大多数lodash的方法)。 如果你将它与构造函数和instanceof一起使用,那么事情会变得有些模糊。


这里的一个解决方案是避免检查instanceof ,并做类似鸭子打字的事情; 不要检查对象的构造函数是否是特定函数,但检查该对象是否具有您期望的属性。

另一种解决方案是,如评论中所建议的,在您的类本身上实现克隆方法,该方法不会使用lodash。

class A() {
    clone() {
        var cloned = new A(); //pass appropriate constructor args
        //make other necessary changes to make the state match
        return cloned;
    }
}

有一篇关于深度克隆的有趣博客文章http://blog.soulserv.net/understanding-object-cloning-in-javascript-part-ii/ 您可以使用作者的深度克隆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()源代码 ] [ 完整源代码 ]

您可以使用Lodash#cloneDeep实用程序。 使用示例:

import * as _ from "lodash";

...

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

您可以使用JSON stringify和parse方法创建自己的深度克隆:

export function deepClone<T>(obj: T): T {
  return JSON.parse(JSON.stringify(obj)) as T;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM