Hone logo
Hone
Problems

TypeScript Class Utility Kit

This challenge focuses on building a small, yet powerful, set of utility functions for working with TypeScript classes. These utilities will help in creating more dynamic and flexible class-based solutions by allowing introspection and modification of class properties and methods at runtime. This is particularly useful in scenarios like framework development, ORMs, or advanced metaprogramming.

Problem Description

You are tasked with creating a TypeScript utility class, ClassUtils, that provides several static methods for interacting with and manipulating classes. These utilities should be robust and handle various class structures.

Your ClassUtils class should implement the following static methods:

  1. getOwnProperties(target: Function): string[]:

    • Returns an array of all own property names (enumerable and non-enumerable, including symbols) of a given class constructor function.
    • This should exclude properties inherited from the prototype chain.
  2. getOwnMethods(target: Function): string[]:

    • Returns an array of all own method names (enumerable and non-enumerable, including symbols) of a given class constructor function.
    • A "method" here is defined as an own property whose value is a function.
    • This should exclude methods inherited from the prototype chain.
  3. hasOwnMethod(target: Function, methodName: string | symbol): boolean:

    • Returns true if the given class constructor function has an own property named methodName that is a function, and false otherwise.
    • This should not consider inherited methods.
  4. getPropertyDescriptor(target: Function, propertyName: string | symbol): PropertyDescriptor | undefined:

    • Returns the PropertyDescriptor for an own property of a given class constructor function.
    • If the property does not exist as an own property on the class itself (not its prototype), it should return undefined.

Examples

Example 1: getOwnProperties

class MyClass {
    static staticProp = 1;
    instanceProp = 2; // Not an own property of the class constructor

    constructor() {}
}

// Expected Output: ["staticProp", "prototype"] (or similar, depending on JS engine internal properties)
console.log(ClassUtils.getOwnProperties(MyClass));

Example 2: getOwnMethods

class Calculator {
    static add(a: number, b: number): number {
        return a + b;
    }

    subtract(a: number, b: number): number {
        return a - b;
    }

    #privateMethod() {
        return "private";
    }

    constructor() {}
}

// Expected Output: ["add", "prototype"] (order might vary)
console.log(ClassUtils.getOwnMethods(Calculator));

Example 3: hasOwnMethod

class Greeter {
    static greet(name: string): string {
        return `Hello, ${name}`;
    }

    sayGoodbye(): void {
        console.log("Goodbye!");
    }

    constructor() {}
}

// Expected Output: true
console.log(ClassUtils.hasOwnMethod(Greeter, "greet"));

// Expected Output: false (instance method, not on the class itself)
console.log(ClassUtils.hasOwnMethod(Greeter, "sayGoodbye"));

// Expected Output: false (method does not exist)
console.log(ClassUtils.hasOwnMethod(Greeter, "farewell"));

Example 4: getPropertyDescriptor

class Configurable {
    static readonly MAX_RETRIES = 3;
    static configurableProp: number | undefined;

    constructor() {}
}

// Expected Output: { value: 3,writable: false,enumerable: false,configurable: false }
console.log(ClassUtils.getPropertyDescriptor(Configurable, "MAX_RETRIES"));

// Expected Output: { value: undefined,writable: true,enumerable: true,configurable: true }
console.log(ClassUtils.getPropertyDescriptor(Configurable, "configurableProp"));

// Expected Output: undefined
console.log(ClassUtils.getPropertyDescriptor(Configurable, "nonExistentProp"));

Constraints

  • The input target to all ClassUtils methods will always be a valid JavaScript Function that represents a class constructor.
  • Property names can be strings or symbols.
  • Methods are defined as own properties whose value is a function.
  • Performance is important, but correctness and adherence to the problem description are paramount. Avoid overly complex or inefficient solutions.

Notes

  • Consider using Object.getOwnPropertyNames(), Object.getOwnPropertySymbols(), and Object.getOwnPropertyDescriptor() to achieve the desired functionality.
  • Remember that the prototype property is an own property of the class constructor itself.
  • The definition of "method" for getOwnMethods and hasOwnMethod is specific: an own property whose value is a function. This means you'll need to check the type of the property's value.
  • Be mindful of how JavaScript handles properties on constructor functions versus their prototypes.
Loading editor...
typescript