Hone logo
Hone
Problems

Dynamic Type Inference from Object Paths in TypeScript

This challenge focuses on building a utility function that dynamically infers the TypeScript type of a property located at a given path within a deeply nested object. This is useful for scenarios where you need to access and type-check properties without knowing their exact structure at compile time, enabling more flexible and dynamic code. The function should traverse the object based on the provided path and return the inferred type.

Problem Description

You are tasked with implementing a function called getTypeByPath that takes two arguments: an object (obj) and a path (path). The path is an array of strings representing the sequence of property names to traverse within the object. The function should return the TypeScript type of the property at the end of the path.

What needs to be achieved:

  • The function should traverse the object based on the provided path.
  • It should return the TypeScript type of the property at the end of the path.
  • If the path is invalid (e.g., a property doesn't exist), the function should return unknown.

Key Requirements:

  • The function must handle nested objects correctly.
  • The function must return the correct TypeScript type, not just any.
  • The function should be robust and handle invalid paths gracefully.

Expected Behavior:

The function should return the type of the property at the specified path. If any property in the path does not exist, it should return unknown.

Edge Cases to Consider:

  • Empty path: Should return unknown.
  • Path with a single property: Should return the type of that property.
  • Path with multiple nested properties: Should return the type of the final property.
  • Object with null or undefined values at intermediate steps in the path.
  • Path leading to a primitive type (string, number, boolean, etc.).
  • Path leading to an array.
  • Path leading to a function.

Examples

Example 1:

Input:
obj: {
  user: {
    profile: {
      name: string,
      age: number
    }
  }
}
path: ['user', 'profile', 'name']
Output: string
Explanation: The path ['user', 'profile', 'name'] leads to the property 'name' within the nested object, which has the type 'string'.

Example 2:

Input:
obj: {
  data: {
    items: [
      { id: number, value: string }
    ]
  }
}
path: ['data', 'items', 0, 'value']
Output: string
Explanation: The path ['data', 'items', 0, 'value'] leads to the 'value' property of the first element (index 0) in the 'items' array, which has the type 'string'.

Example 3:

Input:
obj: {
  settings: {
    theme: 'dark'
  }
}
path: ['settings', 'unknownProperty']
Output: unknown
Explanation: The property 'unknownProperty' does not exist in the 'settings' object, so the function returns 'unknown'.

Example 4:

Input:
obj: {}
path: ['a', 'b']
Output: unknown
Explanation: The object is empty, so the path is invalid and the function returns 'unknown'.

Constraints

  • The object obj can be of any valid TypeScript type.
  • The path path will always be an array of strings.
  • The length of the path can be any non-negative integer.
  • The function should handle potentially large, deeply nested objects without causing stack overflow errors (consider iterative approach).
  • Performance: The function should complete within a reasonable time (e.g., less than 100ms) for typical object sizes.

Notes

  • Consider using TypeScript's type inference capabilities to determine the type of the property at the end of the path.
  • You may need to use type assertions or type guards to handle different types of properties.
  • An iterative approach (using a for loop) is generally preferred over recursion to avoid potential stack overflow errors with deeply nested objects.
  • The return type should be unknown when the path is invalid or the property doesn't exist. Avoid returning any as it defeats the purpose of type safety.
Loading editor...
typescript