深度克隆只读实例

时间:2017-09-16 19:19:23

标签: typescript immutability deep-copy

假设我们有一个带有引用另一个类的属性的类。我希望能够深深克隆一个" Immutable" (或Readonly)实例:

import * as _ from 'lodash'; 

interface IParent{
   name: string;
}

interface IChild{
   name: string;
   parent: IParent;
}

public class Child implements IChild{
   public name: string;
   public parent: string;

   constructor(props: IChild){
      Object.assign(this, props);
   }

   toImmutable(): Readonly<IChild> {
       return _.cloneDeep(this); //lodash deep clone
   }
}

虽然此代码在child实例Readonly上创建了第一个类属性,但仍可以编辑引用的对象:

let child = new Child({ 
   name: 'abc',
   parent: { name: 123 }
});

let immutable = child.toImmutable();
immutable.name = 'abc';  //not allowed
immutable.parent.name = 'abc';  //this is allowed!!!

是否有一个优雅的解决方案可以让我只读取克隆对象的所有内容?

注意: 看起来lodash有一个名为cloneDeepWith的方法,它采用了#34;自定义程序&#34; ...想知道这是否可能朝着正确的方向发展。

1 个答案:

答案 0 :(得分:1)

关键是要创建一个您要使用的自定义类型DeepReadonly<T>,而不是Readonly<>

type DeepReadonly<T> = {
    readonly [K in keyof T]: DeepReadonly<T[K]>;
}

此类型将递归地将readonly属性应用于所有嵌套对象。

See this in playground

type DeepReadonly<T> = {
    readonly [K in keyof T]: DeepReadonly<T[K]>;
}

import * as _ from 'lodash'; 

interface IParent{
   name: string;
}

interface IChild{
   name: string;
   parent: IParent;
}

class Child implements IChild{
   public name: string;
   public parent: IParent;

   constructor(props: IChild){
      Object.assign(this, props);
   }

   toImmutable(): DeepReadonly<IChild> {
       return _.cloneDeep(this); //lodash deep clone
   }
}

let child = new Child({ 
   name: 'abc',
   parent: { name: "123" }
});

let immutable = child.toImmutable();
immutable.name = 'abc';  //not allowed
immutable.parent.name = 'abc';  //not allowed