,假设我们有一个带有引用另一个类的属性的类。我希望能够深入克隆它的"不变"(或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
的方法,该方法采用"定制器" ...想知道这是否可能朝着正确的方向发展。
关键是创建一个自定义类型DeepReadonly<T>
,而不是Readonly<>
:
type DeepReadonly<T> = {
readonly [K in keyof T]: DeepReadonly<T[K]>;
}
这种类型将递归地将读取属性应用于所有嵌套对象。
在操场上参见这一点
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