我需要在 TypeScript 中深度克隆一个对象。这应该不是问题,因为像 Lodash 这样的库为此提供了适当的功能。然而,这些似乎丢弃了类型信息。
> var a = new SomeClass();
> a instanceof SomeClass;
< true
> var b = _.cloneDeep(a);
> b instanceof SomeClass;
< false
有没有办法在保留此键入信息的同时克隆 TypeScript 中的对象?
最佳答案
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
为假的原因是 instanceof
正在检查构造函数:如果函数
是 x 原型(prototype)链中某处的构造函数(参见 instanceof 上的 MDN 文档)。然而,Lodash 在克隆对象时不使用构造函数。它不能。 (它怎么知道要传递什么参数?)它创建了一个普通的 JS 对象,该对象具有克隆对象的所有方法,但不复制它的原型(prototype)链。x instanceof A
返回 true >A
Lodash 的 clone
(实际上是 lodash 的大部分方法)最适用于处理原始 JS 对象。如果您将它与构造函数和 instanceof
一起使用,检查会变得有点模糊。
这里的一个解决方案是避免 instanceof
检查,并做一些类似于 duck typing 的事情;不要检查对象的构造函数是否是特定函数,而是检查对象是否具有您期望的属性。
另一种解决方案是,如评论中所建议的那样,在您的类本身上实现一个克隆方法,它不会使用 lodash。
class A() {
clone() {
var cloned = new A(); //pass appropriate constructor args
//make other necessary changes to make the state match
return cloned;
}
}
关于javascript - TypeScript 中的深度克隆(保留类型),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34201483/