[Typescript] @freeze decorator
function freeze(config?: { unless: () => boolean }) {
return function(target: any, propertyKey: string) {
let value: any;
const getter = function () {
return value;
};
const setter = function (newValue: any) {
const shouldFreeze = !(config?.unless?.() === true);
if (value === undefined || value === null) {
value = newValue;
// Only freeze if newValue is not null or undefined
if (newValue !== null && newValue !== undefined && shouldFreeze) {
Object.freeze(value);
}
}
};
// Delete the original property and re-define it with getter and setter
if (delete target[propertyKey]) {
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
};
}
Usage:
class Example {
@freeze() // No configuration passed, so it will always freeze the property
alwaysFrozenProperty: any;
@freeze({ unless: () => false }) // This will freeze the property
myProperty: any;
@freeze({ unless: () => true }) // This will not freeze the property due to the unless condition
anotherProperty: any;
}
const obj = new Example();
obj.alwaysFrozenProperty = { name: "Frozen" };
obj.alwaysFrozenProperty.name = "Modified"; // No effect, as the object is frozen
console.log(obj.alwaysFrozenProperty); // Outputs: { name: "Frozen" }
obj.myProperty = { name: "Test" };
obj.myProperty.name = "Changed"; // This will have no effect because `myProperty` is frozen
console.log(obj.myProperty); // Outputs: { name: "Test" }
obj.anotherProperty = { name: "Initial" }; // This will not freeze the property
obj.anotherProperty.name = "Modified"; // This will modify the property because it's not frozen
console.log(obj.anotherProperty); // Outputs: { name: "Modified" }