Implementing Accessor Decorators in TypeScript
Accessor decorators in TypeScript provide a powerful way to control how properties are accessed and modified within a class. This challenge will guide you through creating decorators that can log property access (both get and set) and potentially modify the values being accessed or set. Understanding and implementing accessor decorators is crucial for building robust and maintainable TypeScript applications.
Problem Description
You are tasked with creating three TypeScript decorators: logGet, logSet, and validate.
logGet: This decorator should log a message to the console whenever a property is accessed (read). The message should include the property name and its value.logSet: This decorator should log a message to the console whenever a property is modified (written to). The message should include the property name, the old value, and the new value.validate: This decorator should take a validation function as an argument. The validation function should accept the new value being set and return a boolean indicating whether the value is valid. If the validation function returnsfalse, the property should not be set, and an error message should be logged to the console indicating the validation failure.
The goal is to apply these decorators to a class's properties to add logging and validation functionality without directly modifying the class's original code.
Key Requirements:
- The decorators must work correctly with both primitive and object properties.
- The
validatedecorator must prevent invalid values from being assigned to the property. - The logging messages should be clear and informative.
- The code should be well-structured and easy to understand.
Expected Behavior:
When a decorated property is accessed, logGet should log the property's value. When a decorated property is set, logSet should log the old and new values. If validate is applied, the validation function should be called before the property is set. If the validation function returns false, the property should not be set, and an error message should be logged.
Examples
Example 1:
class Person {
@logGet
@logSet
@validate(value => value > 0)
age: number = 0;
name: string = "John Doe";
constructor(age: number, name: string) {
this.age = age;
this.name = name;
}
}
const person = new Person(30, "Alice");
person.age = 25;
console.log(person.age);
person.age = -5; // Should not update age and log an error
console.log(person.age);
Output:
Logging: age: 30
Logging: age: 25
Logging: age: 25
Validation Error: Age must be greater than 0.
Logging: age: 25
Example 2:
class Product {
@logGet
@logSet
price: number = 10;
@logGet
@logSet
description: string = "";
}
const product = new Product();
product.price = 20;
console.log(product.price);
product.description = "Awesome Product";
console.log(product.description);
Output:
Logging: price: 10
Logging: price: 20
Logging: price: 20
Logging: description: ""
Logging: description: Awesome Product
Constraints
- The validation function passed to the
validatedecorator must be a function that accepts a single argument (the new value) and returns a boolean. - The decorators should be compatible with standard TypeScript class structures.
- The logging messages should be concise and informative.
- The code should be written in clean, readable TypeScript.
Notes
- Consider using the
getandsetmethods within the decorator factory to intercept property access and modification. - The
validatedecorator requires careful handling to prevent the property from being set if the validation fails. - Think about how to handle different data types when validating. The validation function should be flexible enough to handle various types.
- The order of decorator application matters.
validateshould be applied beforelogSetto prevent invalid values from being logged. - Error logging can be done using
console.errorfor better distinction.