【问题标题】:Deep cloning Entity instances in Typescript?在 Typescript 中深度克隆实体实例?
【发布时间】:2019-02-27 09:51:52
【问题描述】:

正在尝试:

/**
 * Deep clones an array of instances of type T and returns a new array.
 * @param array The array to deep clone
 * @return A new deep clone of the array argument
 *
 * @example
<pre>
  const original = [new Todo(), new Todo()];
  const result = [new Todo(), new Todo()];
  expect(deepClone(original)).to.eql(result);
</pre>
*/
export function deepClone<T extends Object>(array: T[]): T[] {
  return array.map((e:T) => ({...e}));
}

打字稿说:

[ts] 传播类型只能从对象类型创建。

不应该T extends Object 处理这个吗?

【问题讨论】:

  • 不幸的是,您必须使用类型断言。 array.map((e:T) =&gt; (&lt;object&gt;{...e})); 这很丑,但如果你知道自己在做什么,它就可以工作。仅供参考,您在约束中使用了错误的类型。应该是object
  • 我试过了,但现在显示Type 'object' is not assignable to type 'T'.
  • @AluanHaddad 天气越来越暖和了,但现在它说:[ts] Type 'object' cannot be converted to type 'T'.
  • 所以在两者之间添加&lt;unknown&gt;array.map((e) =&gt; &lt;T&gt;(&lt;unknown&gt;&lt;object&gt;{...e}));

标签: javascript arrays typescript


【解决方案1】:

关于您的实际实现,您应该考虑使用老伙伴 JSON 来帮助您解决这个问题。

var array:Array<number> = [1,2,3];
var deepClone = clone(array);
deepClone[0] = 99;
console.log({ array, deepClone });  // returns [1,2,3] & [99,2,3]

function clone<T>(array:T[]) {
return JSON.parse(JSON.stringify(array)) as Array<T>;
}

【讨论】:

    【解决方案2】:

    我用这个方法

    https://stackblitz.com/edit/typescript-qmzgf7

    const clone = obj =>
      Array.isArray(obj)
        ? obj.map(item => clone(item))
        : obj instanceof Date
          ? new Date(obj.getTime())
          : (typeof obj === 'object') && obj
            ? Object.getOwnPropertyNames(obj).reduce((o, prop) => ({ ...o, [prop]: clone(obj[prop]) }), {})
            : obj;
    

    它不适用于您可能遇到的所有 JavaScript 对象,但它可能适用于来自 JSON 格式的服务器调用的任何内容。

    【讨论】:

      【解决方案3】:

      如果你用扩展运算符复制一个对象,你的新对象将不是一个类的实例,而是一个没有类型的文字对象,所以它不会是现有对象的真正克隆。

      如果您要克隆的对象是由您定义的(不是外部库),您可以执行以下操作:

      export function deepClone(array: any[]): any[] {
        return array.map((e:any) => (new e.constructor(e)));
      }
      

      然后在你的类中被克隆:

      constructor(obj: any) {
         Object.assign(this, obj);
      }
      

      【讨论】:

      • 这仅适用于顶级属性是字符串和数字等值类型的情况。引用对象是对象的同一实例,而不是深层克隆。
      • @AdrianBrand 你是对的,这可以通过在每个具有非原始类型的属性上定义一个 setter 来解决
      • 我质疑解释的有效性。这感觉像是编译器的限制,而不是答案中所述的方法的问题。唯一的问题是:结果是否满足接口 T? JavaScript 和 TypeScript 中都没有“类的实例”之类的东西。
      • @NikolaMihajlović 如 cmets 所述,这是 Typescript 的限制。我的回答指出{...e} 方法不会创建类似的对象,因为即使您不想将其称为“类的实例”,Javascript 中也有 are 类型,并且许多相关关键字(instanceoftypeofnewconstructor 等...)。并且扩展运算符不反映源对象的类型。
      猜你喜欢
      • 1970-01-01
      • 2017-09-01
      • 1970-01-01
      • 2020-01-09
      • 2017-11-17
      • 1970-01-01
      • 2010-11-30
      • 2011-11-27
      相关资源
      最近更新 更多