I wish I could post my project verbatim for this question, but I cannot.
Essentially, I have the following classes:
class Lowest {
someValue: string
constructor(someValue: string) {
this.someValue = someValue
}
}
class Middle {
lowest: Lowest
constructor(someValue: string) {
this.lowest = new Lowest(someValue)
}
}
class Highest {
private _middle: Middle
otherValue: SomeOtherClass
// normal getter
public get middle(): Middle {
return this._middle
}
public set middle(next: Middle) {
this._middle = next
// notice: when `_middle` is set, I update another property!
otherValue.doSomething(this._middle)
}
constructor(config: { someValue: string }) {
this.middle = new Middle(config.somevalue)
}
}
In some places in my program, I have a reference to a Highest instance and need to alter its middle.lowest.someValue sub-property. Now, for architectural reasons that I cannot really describe here, I need to update the Highest.otherValue property whenever Highest.middle. As I am using TypeScript, I simply perform this operation in the setter for Highest.middle. As such, I cannot just straight up set Highest.middle.lowest to some value.
My first approach was:
const nextMiddle = Object.assign({}, highestInstance.middle)
nextMiddle.lowest.someValue = "some other thing"
highestInstance.middle = nextMiddle
However, this ended up causing some very strange issues. Now, I had no real technical need for performing a deep clone of nextMiddle, so I overcame it with the following code:
const nextMiddle = highestInstance.middle
nextMiddle.lowest.someValue = "some other thing"
highestInstance.middle = nextMiddle
While I was experimenting with the best fix, I implemented a Middle.copy() method that basically just calls new Middle() and new Lowest() with the values from the previous instance. This also solved my technical issues, but left me even more confused.
I understand that there's a big difference between simply re-assigning highestInstance.middle and using Object.assign() to clone it, but I don't understand why there does not seem to be a difference between Object.assign() and new Middle()
What are the real differences with these three methods of cloning/re-assignment?
had no real technical need for performing a deep clone of nextMiddle, so I overcame it with the following code:
Object.assign({}, highestInstance.middle) is creating a shallow copy and not a deep copy.
The issue here is using Middle Setter is forcing yourself to perform otherValue: SomeOtherClass only when middle is updated.
it will update it even if you just do just :
high.middle.lowest.someValue = 'new value'
high.middle = high.middle; // setter triggered
A possible solution is to create a call-back chain rather than using a setter:
type voidFun = () => void;
class Lowest {
private _someValue: string
public get someValue(): string {
return this._someValue
}
private update?: voidFun; // create an optional callback
public set someValue(next: string) {
this._someValue = next
this.update?.call(undefined);
}
constructor(someValue: string, fun?: voidFun) {
this._someValue = someValue
this.update = fun;// pass down
}
}
class Middle {
lowest: Lowest;
constructor(someValue: string, fun?: voidFun) {
this.lowest = new Lowest(someValue, fun)
}
}
class Highest {
private _middle: Middle
otherValue: any = {};
// normal getter
public get middle(): Middle {
return this._middle
}
// now you dont need middle setting so it cant be updated by anyone directly
// if you still want to have you can have it too
private callBack = () => {
console.log('lower was update');
this.otherValue.myMiddle = this._middle.lowest.someValue;
}
constructor(config: { someValue: string } = { someValue : 'constr' }) {
this._middle = new Middle(config.someValue, this.callBack)
}
}
let high = new Highest()
high.middle.lowest.someValue = 'new value'
// high.middle = high.middle; // now not possible unless you create setter
console.log('updated middle high',high)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With