Property Decorators in TypeScript: Validation and Transformation
Property decorators are a powerful feature in TypeScript that allow you to modify or enhance class properties. This challenge will guide you in creating decorators that both validate and transform property values, ensuring data integrity and consistency within your classes. Understanding and implementing property decorators is crucial for building robust and maintainable TypeScript applications.
Problem Description
You are tasked with creating two property decorators: validateEmail and uppercaseString. The validateEmail decorator should ensure that a string property contains a valid email address format. The uppercaseString decorator should convert a string property to uppercase upon assignment.
What needs to be achieved:
- Implement the
validateEmaildecorator to check if a string property conforms to a basic email format (e.g., contains "@" and "."). It should throw an error if the validation fails. - Implement the
uppercaseStringdecorator to automatically convert the value of a string property to uppercase when it's assigned. - Apply both decorators to a sample class demonstrating their functionality.
Key Requirements:
- The decorators must be reusable and applicable to any string property.
- The
validateEmaildecorator must throw anErrorobject with a descriptive message if the email format is invalid. - The
uppercaseStringdecorator must not affect the original value; it should only modify the property's value. - The decorators should be implemented using TypeScript's decorator syntax.
Expected Behavior:
- When a property decorated with
validateEmailis assigned an invalid email address, an error should be thrown. - When a property decorated with
uppercaseStringis assigned a string, the property should store the uppercase version of that string.
Edge Cases to Consider:
- What happens if the property is not a string? (The decorators should ideally handle this gracefully, perhaps by doing nothing or throwing a different error.)
- What happens if the property is already initialized before the decorator is applied? (Consider how to handle existing values.)
- Consider the order in which decorators are applied. Does it matter?
Examples
Example 1:
Input:
class User {
@validateEmail
email: string = "invalid-email";
}
const user = new User();
Output:
Error: Invalid email format.
Explanation: The validateEmail decorator detects the invalid email format and throws an error during instantiation.
Example 2:
Input:
class Product {
@uppercaseString
name: string = "product name";
}
const product = new Product();
console.log(product.name);
Output:
PRODUCT NAME
Explanation: The uppercaseString decorator converts the initial value of the name property to uppercase.
Example 3: (Edge Case)
Input:
class Settings {
@validateEmail
configEmail: string | number = 123;
}
const settings = new Settings();
Output:
(No error thrown, or a more specific error indicating a non-string type)
Explanation: The decorator should handle the case where the property is not a string gracefully. Ideally, it would either do nothing or throw an error indicating the incorrect type.
Constraints
- The email validation should be a basic check (presence of "@" and "."). Complex regex validation is not required.
- The decorators must be implemented using TypeScript's decorator syntax.
- The code should be well-structured and readable.
- The
validateEmaildecorator must throw anErrorobject.
Notes
- Remember that decorators are essentially functions that modify classes, methods, or properties.
- The
validateEmaildecorator should be applied before the property is assigned a value. - Consider using TypeScript's type system to ensure type safety within your decorators.
- Think about how to handle properties that are already initialized when the decorator is applied. You might need to check if the property already has a value before applying the transformation.