Hone logo
Hone
Problems

TypeScript Type Inference Helpers

TypeScript's powerful type inference system is a cornerstone of its safety and developer experience. However, sometimes we need to go beyond the default inference to extract specific types or to create more flexible types. This challenge asks you to implement utility types that help in inferring and manipulating types within TypeScript, making your code more robust and maintainable.

Problem Description

Your task is to create a set of TypeScript utility types that can be used to infer and transform types. Specifically, you need to implement the following:

  1. InferFunctionReturnType<T>: A utility type that infers the return type of a function type T.
  2. InferParameterType<T, Index>: A utility type that infers the type of the parameter at a specific Index within a function type T.
  3. InferObjectKeyType<T>: A utility type that infers the union of all possible keys (both string and number literal types) of an object type T.
  4. InferObjectValueType<T>: A utility type that infers the union of all possible value types of an object type T.

These utility types should work with generic type parameters and handle various function and object signatures.

Examples

Example 1: InferFunctionReturnType

type MyFunction = (a: number, b: string) => boolean;

type ReturnType = InferFunctionReturnType<MyFunction>;
// Expected Output: boolean

Explanation: The InferFunctionReturnType takes MyFunction and correctly extracts its return type, which is boolean.

Example 2: InferParameterType

type AnotherFunction = (x: { id: number }, y: string[]) => void;

type FirstParamType = InferParameterType<AnotherFunction, 0>;
// Expected Output: { id: number }

type SecondParamType = InferParameterType<AnotherFunction, 1>;
// Expected Output: string[]

Explanation: InferParameterType allows us to precisely target and extract the type of a parameter based on its index in the function's parameter list.

Example 3: InferObjectKeyType

type MyObject = {
  name: string;
  age: number;
  isActive: boolean;
  [key: string]: any; // Index signature
  0: 'zero'; // Numeric index signature
};

type ObjectKeys = InferObjectKeyType<MyObject>;
// Expected Output: 'name' | 'age' | 'isActive' | string | 0

Explanation: This type infers all literal string keys, literal number keys, and any index signature keys from the object type.

Example 4: InferObjectValueType

type AnotherObject = {
  id: number;
  data: { message: string };
  status: 'pending' | 'completed';
  nested: { value: boolean };
};

type ObjectValues = InferObjectValueType<AnotherObject>;
// Expected Output: number | { message: string } | 'pending' | 'completed' | { value: boolean }

Explanation: This type infers all distinct value types present in the object.

Example 5: Edge Case for InferParameterType

type VariadicFunction = (...args: number[]) => string;

type VariadicParamType = InferParameterType<VariadicFunction, 0>;
// Expected Output: number[]

Explanation: Handles variadic parameters correctly. If no index is explicitly provided for a variadic function, it should infer the tuple type of arguments. However, for this specific challenge, we are targeting a single parameter index.

Constraints

  • All implemented utility types must be defined purely using TypeScript's built-in conditional types, mapped types, and template literal types. No external libraries or runtime code are allowed.
  • The solution should be written entirely in TypeScript.
  • The utility types should be robust and handle various function and object shapes, including optional parameters, rest parameters, and index signatures.
  • Performance is not a primary concern for this challenge, but the types should be reasonably efficient to compile.

Notes

  • Consider how to handle cases where the input type might not be a function or an object as expected. For example, what should InferFunctionReturnType return if T is number? (Hint: The goal is to infer from specific types, so focusing on valid inputs is key.)
  • For InferParameterType, you might need to use indexed access types and conditional types to navigate the parameters.
  • For InferObjectKeyType and InferObjectValueType, think about how to iterate over the properties of an object type.
  • The keyof operator will be crucial for inferring keys.
  • You might need to explore advanced conditional type patterns to extract the desired information.
Loading editor...
typescript