Hone logo
Hone
Problems

TypeScript Decorator Factory Type Generation

Decorator factories are powerful tools in TypeScript for configuring decorators before they are applied to classes, methods, or properties. This challenge focuses on creating robust and type-safe decorator factory functions that can generate decorators with varying configurations. You will implement a system that allows for parameterized decorators and ensures type safety throughout the process.

Problem Description

Your task is to create a TypeScript decorator factory that can generate decorators with configurable parameters. Specifically, you need to implement a createLoggerDecorator function. This factory will take an options object as an argument, which will determine the behavior of the generated decorator. The generated decorator should log messages to the console when a class or its methods are accessed or invoked.

Key Requirements:

  1. Decorator Factory: Implement a function createLoggerDecorator that accepts an options object.
  2. Options Object: The options object should have an optional prefix property (string) to prepend to log messages.
  3. Generated Decorator: The createLoggerDecorator function should return a decorator function.
  4. Decorator Application: The generated decorator should be applicable to classes and class methods.
  5. Logging Behavior:
    • When applied to a class, the decorator should log a message indicating the class is being "initialized" (or similar, upon instantiation).
    • When applied to a method, the decorator should log a message before the method is invoked, including the method name and any arguments passed to it.
    • If a prefix is provided in the options, it should be prepended to all log messages.
  6. Type Safety: Ensure that the factory and the generated decorator are as type-safe as possible, leveraging TypeScript's features.

Expected Behavior:

When a class decorated with the factory-generated decorator is instantiated, a log message (potentially prefixed) should appear. When a method on that class is called, a log message detailing the method call and its arguments (potentially prefixed) should appear.

Edge Cases:

  • What happens if no options are provided to the factory? The decorator should still function with default behavior (no prefix).
  • Consider how to handle methods with no arguments.
  • Consider how to log arguments of different types (primitives, objects, arrays).

Examples

Example 1: Basic Class Decorator

// Assume createLoggerDecorator is implemented correctly

@createLoggerDecorator()
class MyService {
  greet(name: string) {
    console.log(`Hello, ${name}!`);
  }
}

const service = new MyService(); // Should log: "[MyService] initialized"
service.greet("Alice"); // Should log: "[MyService.greet] called with arguments: [ 'Alice' ]"

Output Explanation:

The @createLoggerDecorator() factory is called without options, so the default behavior (no prefix) is used. When MyService is instantiated, a log message indicating its initialization is printed. When greet is called, a log message shows the method name and its argument.

Example 2: Decorator Factory with Prefix

// Assume createLoggerDecorator is implemented correctly

@createLoggerDecorator({ prefix: "[APP]" })
class DataProcessor {
  process(data: number[]): number {
    const sum = data.reduce((acc, val) => acc + val, 0);
    console.log(`Processed data: ${sum}`);
    return sum;
  }
}

const processor = new DataProcessor(); // Should log: "[APP] [DataProcessor] initialized"
processor.process([1, 2, 3]); // Should log: "[APP] [DataProcessor.process] called with arguments: [ [ 1, 2, 3 ] ]"

Output Explanation:

The @createLoggerDecorator({ prefix: "[APP]" }) factory is called with a prefix. This prefix is prepended to all generated log messages. The output clearly shows the [APP] prefix before the standard logging information.

Example 3: Method Decorator with Multiple Arguments

// Assume createLoggerDecorator is implemented correctly

@createLoggerDecorator({ prefix: "[DEBUG]" })
class Calculator {
  add(a: number, b: number): number {
    return a + b;
  }
}

const calc = new Calculator(); // Should log: "[DEBUG] [Calculator] initialized"
const result = calc.add(5, 10); // Should log: "[DEBUG] [Calculator.add] called with arguments: [ 5, 10 ]"
console.log(`Result: ${result}`);

Output Explanation:

This example demonstrates logging with a prefix and multiple arguments passed to a method. The decorator correctly captures and logs both arguments 5 and 10.

Constraints

  • The createLoggerDecorator function should accept an optional options object of type { prefix?: string }.
  • The decorator should be compatible with ESNext decorators (target esnext or es2017 and above in tsconfig.json).
  • Ensure that the decorated class constructor is called as expected.
  • Ensure that the decorated methods are executed with their original functionality.

Notes

  • You will need to use the appropriate decorator syntax for classes and methods.
  • Remember that class decorators receive the constructor function as their argument, and method decorators receive the prototype, property name, and property descriptor.
  • Consider how you will access the class name within the decorator when applied to a class.
  • The console.log statements within your decorators are your primary output mechanism.
  • Think about how to handle different types of arguments when logging them. The JSON.stringify or simply passing them to console.log might be useful for displaying arguments.
Loading editor...
typescript