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

标签 javascript typescript lodash

我需要在 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 instanceof A 返回 true >A 是 x 原型(prototype)链中某处的构造函数(参见 instanceof 上的 MDN 文档)。然而,Lodash 在克隆对象时不使用构造函数。它不能。 (它怎么知道要传递什么参数?)它创建了一个普通的 JS 对象,该对象具有克隆对象的所有方法,但不复制它的原型(prototype)链。

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/

相关文章:

javascript - 获取对象数组中重复对象的列表

javascript - 查找容器中的所有可见元素

javascript - 在 PHP 中重写 JSON 数组以便 jQuery 可以读取它?

javascript - 视差效果不适用于移动版 chrome 浏览器

javascript - Chrome 消息扩展程序 : From injected script to background

Angular 4在选择更改时获取属性数据值

javascript - LoDash:减少 Angular 返回 0

javascript - 将 Hooks 与 Redux 一起使用——不好的做法?

使用 defineProperty 的 JavaScript 原型(prototype)继承

typescript - 如何在 TypeScript 中对映射和集合强制执行更严格的类型?