Class Decorators in TypeScript: Logging and Validation
Class decorators are a powerful feature in TypeScript that allow you to modify or enhance classes at definition time. This challenge will guide you through creating decorators that add logging and validation functionality to your classes, demonstrating a practical application of this advanced TypeScript concept. Understanding class decorators is crucial for building modular, reusable, and maintainable code.
Problem Description
You are tasked with creating two class decorators: LogDecorator and ValidateDecorator.
LogDecorator: This decorator should wrap the constructor of the decorated class and log a message to the console whenever a new instance of the class is created. The log message should include the class name and the arguments passed to the constructor.ValidateDecorator: This decorator should add avalidatemethod to the decorated class. This method should take an object as input, and if any of the object's properties do not match the types defined in the class's constructor parameters, it should throw an error with a descriptive message.
Key Requirements:
- The decorators must be implemented using TypeScript's decorator syntax.
- The
LogDecoratormust correctly log the class name and constructor arguments. - The
ValidateDecoratormust correctly validate the input object against the class's constructor parameters and throw an error if validation fails. - The decorators should be reusable and applicable to any class.
- The
validatemethod added byValidateDecoratorshould be accessible as a method on the decorated class instance.
Expected Behavior:
When a class is decorated with LogDecorator, creating a new instance of that class should result in a log message being printed to the console. When a class is decorated with ValidateDecorator, a validate method should be added to the class, allowing you to validate objects against the class's constructor parameters.
Edge Cases to Consider:
- Classes with no constructor parameters.
- Classes with optional constructor parameters.
- Classes with complex constructor parameters (e.g., nested objects, arrays).
- Incorrect input types passed to the
validatemethod.
Examples
Example 1:
// Class definition
class Person {
constructor(public name: string, public age: number) {}
}
// Decorator application
@LogDecorator
@ValidateDecorator
class MyPerson extends Person {}
// Usage
const person1 = new MyPerson("Alice", 30); // Should log "New MyPerson instance created with arguments: { name: 'Alice', age: 30 }"
const person2 = { name: "Bob", age: "40" }; // Should throw an error during validation
try {
const person = new MyPerson(person2);
} catch (error) {
console.error(error.message); // Expected output: "Validation error: age must be a number"
}
Example 2:
// Class definition
class Product {
constructor(public id: number, public name: string) {}
}
// Decorator application
@LogDecorator
@ValidateDecorator
class MyProduct extends Product {}
// Usage
const product1 = new MyProduct(123, "Laptop"); // Should log "New MyProduct instance created with arguments: { id: 123, name: 'Laptop' }"
const product2 = { id: "456", name: "Tablet" }; // Should throw an error during validation
try {
const product = new MyProduct(product2);
} catch (error) {
console.error(error.message); // Expected output: "Validation error: id must be a number"
}
Constraints
- The code must be written in TypeScript.
- The decorators must be implemented using the standard TypeScript decorator syntax.
- The
validatemethod should throw an error if validation fails. - The logging should be done using
console.log. - The validation should check for type mismatches only. No complex validation rules are required (e.g., range checks).
- The solution should be well-structured and readable.
Notes
- Consider using the
constructordecorator to access the constructor parameters. - The
ValidateDecoratorneeds to inspect the constructor signature to determine the expected types. TypeScript's type system can be leveraged for this. - Think about how to handle optional constructor parameters.
- The
validatemethod should provide clear and informative error messages. - This challenge focuses on the core concepts of class decorators. Error handling and more advanced validation logic can be added as extensions.