Hone logo
Hone
Problems

Lazy Type Evaluation in TypeScript

Lazy type evaluation, also known as type inference at runtime, allows you to determine the type of a variable or expression based on its usage rather than at compile time. This is particularly useful when dealing with dynamic data or situations where the type isn't immediately known. This challenge asks you to implement a basic system for lazy type evaluation in TypeScript, enabling type determination based on operations performed on a value.

Problem Description

You need to create a LazyType class that wraps a value and allows you to determine its type after it has been used in some operations. The LazyType class should provide the following functionality:

  1. Constructor: Accepts a value of any type as input.
  2. operate(func): Takes a function func as input. This function should accept the wrapped value as input and return a new value. The operate method should execute func with the wrapped value, store the result, and return the result. Crucially, the type of the wrapped value should be inferred based on the return type of func.
  3. getType(): Returns the inferred type of the wrapped value. This type should be determined based on the last operate call. If no operate calls have been made, it should return unknown.

The goal is to demonstrate how TypeScript can infer types dynamically based on how a value is used, rather than relying solely on compile-time type information.

Examples

Example 1:

Input:
const lazy = new LazyType(10);
const result1 = lazy.operate(x => x * 2);
const type1 = lazy.getType();

Output:
result1: 20
type1: number
Explanation: The initial value is 10. The `operate` function multiplies it by 2, returning 20. The type is inferred as `number` based on the return type of the function.

Example 2:

Input:
const lazy = new LazyType("hello");
const result2 = lazy.operate(s => s.toUpperCase());
const type2 = lazy.getType();

Output:
result2: "HELLO"
type2: string
Explanation: The initial value is "hello". The `operate` function converts it to uppercase, returning "HELLO". The type is inferred as `string` based on the return type of the function.

Example 3: (Edge Case - No Operations)

Input:
const lazy = new LazyType(true);
const type3 = lazy.getType();

Output:
type3: unknown
Explanation: No `operate` calls were made, so the type remains `unknown`.

Example 4: (Complex Scenario - Chaining Operations)

Input:
const lazy = new LazyType(5);
const result4_1 = lazy.operate(x => x + 1);
const result4_2 = lazy.operate(y => y * 3);
const type4 = lazy.getType();

Output:
result4_1: 6
result4_2: 18
type4: number
Explanation: The value starts as 5. The first `operate` adds 1, resulting in 6. The second `operate` multiplies by 3, resulting in 18. The type is inferred as `number` based on the return type of the last operation.

Constraints

  • The operate function must be a function that accepts the wrapped value and returns a new value.
  • The LazyType class should handle values of any valid TypeScript type.
  • The inferred type should accurately reflect the return type of the last operate function called.
  • The getType() method should return unknown if no operate calls have been made.
  • The code should be well-structured and readable.

Notes

  • Consider using TypeScript's type inference capabilities to simplify the implementation.
  • Think about how to store the inferred type within the LazyType class.
  • This is a simplified example of lazy type evaluation. Real-world implementations can be significantly more complex.
  • Focus on demonstrating the core concept of type inference based on runtime operations. You don't need to handle every possible edge case or error condition.
Loading editor...
typescript