Hone logo
Hone
Problems

Type-Safe Return Type Helper in TypeScript

This challenge asks you to create a utility function in TypeScript that infers and returns the return type of a given function. This is useful for creating higher-order functions, decorators, or type transformations where you need to work with the return type of another function without explicitly specifying it. The goal is to create a robust and type-safe solution that handles various function signatures.

Problem Description

You need to implement a function called getReturnType that takes a function as input and returns its return type. The function should leverage TypeScript's type inference capabilities to accurately determine the return type, even for complex function signatures involving generics, optional parameters, and union types.

Key Requirements:

  • Type Inference: The function must accurately infer the return type of the input function.
  • Generics: The function should work correctly with functions that use generics.
  • Optional Parameters: The function should handle functions with optional parameters.
  • Union Types: The function should handle functions that return union types.
  • Void Return Type: The function should correctly identify and return void for functions that don't return a value.
  • No Runtime Execution: The function should only perform type analysis and not execute the input function.

Expected Behavior:

The getReturnType function should return a TypeScript type representing the return type of the input function. This type can then be used in other type operations or declarations.

Edge Cases to Consider:

  • Functions with no return statement (should return void).
  • Functions that explicitly return undefined or null.
  • Functions with complex generic type parameters.
  • Functions with multiple return paths with different types (should return a union type).
  • Functions that return promises (should return Promise<return_type>).

Examples

Example 1:

const add = (a: number, b: number): number => {
  return a + b;
};

// Usage:
type ReturnTypeAdd = ReturnType<typeof add>; // Should be 'number'

Explanation: The add function returns a number. getReturnType should correctly infer and return the type number.

Example 2:

const greet = (name?: string): void => {
  console.log(`Hello, ${name || 'World'}`);
};

// Usage:
type ReturnTypeGreet = ReturnType<typeof greet>; // Should be 'void'

Explanation: The greet function has an optional parameter and returns nothing (void). getReturnType should correctly infer and return the type void.

Example 3:

const fetchData = async (): Promise<string> => {
  return "Data fetched!";
};

// Usage:
type ReturnTypeFetchData = ReturnType<typeof fetchData>; // Should be 'Promise<string>'

Explanation: The fetchData function returns a Promise that resolves to a string. getReturnType should correctly infer and return the type Promise<string>.

Example 4:

const processData = <T>(data: T): T | null => {
  if (!data) {
    return null;
  }
  return data;
};

// Usage:
type ReturnTypeProcessData = ReturnType<typeof processData<number>>; // Should be 'number | null'

Explanation: The processData function is generic and returns either the input type or null. getReturnType should correctly infer and return the union type number | null.

Constraints

  • The solution must be written in TypeScript.
  • The solution must use TypeScript's built-in type inference capabilities.
  • The solution must not execute the input function. It should only perform type analysis.
  • The solution should be reasonably efficient. While performance is not the primary concern, avoid unnecessarily complex or inefficient type operations.
  • The solution should handle a wide range of function signatures, including those with generics, optional parameters, union types, and promises.

Notes

Consider using TypeScript's ReturnType<typeof func> utility type. Your task is to essentially reimplement this utility type. Think about how you can extract the return type from the function's type definition. Pay close attention to how TypeScript handles generics and union types when inferring return types. The core challenge lies in correctly handling the function's type signature to extract the return type information.

Loading editor...
typescript