I have recently implemented a class using a property decorator that sets a flag within the class whenever a decorated property is updated. However, I am encountering an issue when trying to copy values from one instance of the class to another. It seems like setting the value of a property on one object also changes the value on another object, almost as if the property is static. I am relatively new to JavaScript and TypeScript, so I must have overlooked something. Can anyone help me identify where I went wrong?
After running the code snippet below, the following output is logged:
Setting propNum from undefined to 0
testclass.ts:18 Setting propNum from 0 to 123
test.spec.ts:13 t1.propNum = 123
test.spec.ts:14 t2.propNum = 123
The expected behavior is for t1.propNum to remain zero.
Decorating Function
//
// Property decorator used to automatically set a dirty flag for any decorated property
//
function testProperty( target: any, key: string ) {
// Initialize property value
var _val = this[key];
// Define property getter
function getter() {
return _val;
};
// Define property setter
function setter( newVal ) {
if ( _val != newVal ) {
console.log( `Setting ${key} from ${_val} to ${newVal}` );
_val = newVal;
this._dirty = true;
}
};
//
// Delete original property and re-define it with custom getter & setter
//
if ( delete this[key] ) {
// Create new property with customized getter and setter
Object.defineProperty( target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
}
TestClass Definition
export class TestClass {
private _dirty: boolean;
@testProperty
public propNum: number = 0;
constructor() {
this._dirty = false;
}
public copyFrom( tc: TestClass ) {
this.propNum = tc.propNum;
}
}
Testing Code
describe( 'Copy Class Test', () => {
it( 'Copy Test', () => {
var t1 = new TestClass();
var t2 = new TestClass();
t2.propNum = 123;
console.log( `t1.propNum = ${t1.propNum}` );
console.log( `t2.propNum = ${t2.propNum}` );
expect( t1.propNum ).toBe( 0 );
t1.copyFrom( t2 );
expect( t1.propNum ).toBe( 123 );
});
});