Hone logo
Hone
Problems

Safe Type Handling with Unknown Helpers in TypeScript

TypeScript's unknown type represents a value that could be of any type, but unlike any, it forces you to perform type checks before using it. This challenge focuses on creating utility functions to safely work with unknown types, providing a more robust and type-safe way to handle potentially untyped data. Implementing these helpers will improve code reliability and prevent runtime errors when dealing with external data sources or dynamic content.

Problem Description

You are tasked with creating a set of TypeScript utility functions to assist in safely handling values of type unknown. These functions should provide a way to narrow down the type of an unknown value and perform operations on it with confidence. Specifically, you need to implement the following:

  1. isType<T>(value: unknown): value is T: A type predicate function that checks if a given unknown value is of a specific type T. It should return true if the value is of type T and false otherwise. Crucially, it should narrow the type of value to T within any code block where it returns true.

  2. asType<T>(value: unknown): T | undefined: A function that attempts to cast an unknown value to a specific type T. If the value is not of type T, it should return undefined. This function should not throw an error; instead, it should gracefully handle the case where the cast fails.

  3. extractType<T>(value: unknown): T extends never ? never : T: A function that extracts the type of a value if it is known, otherwise returns never. This is useful for inferring types from unknown values.

Examples

Example 1:

Input:
const data: unknown = 123;

// Using isType
function processData(data: unknown) {
  if (isType<number>(data)) {
    console.log(data + 1); // data is now known to be a number
  } else {
    console.log("Data is not a number");
  }
}

processData(data);

// Using asType
const num: number | undefined = asType<number>(data);
if (num !== undefined) {
  console.log(num * 2);
}

// Using extractType
const extractedType = extractType<number | string>(data);
console.log(extractedType); // Output: number

Output:

124
246
number

Explanation: isType correctly identifies data as a number, allowing for safe arithmetic operations. asType successfully casts data to a number. extractType correctly infers the type as number.

Example 2:

Input:
const data: unknown = "hello";

// Using isType
function processData(data: unknown) {
  if (isType<number>(data)) {
    console.log(data + 1);
  } else {
    console.log("Data is not a number");
  }
}

processData(data);

// Using asType
const num: number | undefined = asType<number>(data);
if (num !== undefined) {
  console.log(num * 2);
}

// Using extractType
const extractedType = extractType<number | string>(data);
console.log(extractedType);

Output:

Data is not a number
undefined
string

Explanation: isType correctly identifies that data is not a number. asType returns undefined because the cast to number fails. extractType correctly infers the type as string.

Example 3: (Edge Case - never)

Input:
const data: unknown = null;

// Using extractType
const extractedType = extractType<null>(data);
console.log(extractedType);

Output:

null

Explanation: extractType correctly infers the type as null.

Constraints

  • All functions must be written in TypeScript.
  • The isType function must be a type predicate.
  • The asType function must not throw errors. It should return undefined if the cast fails.
  • The extractType function should correctly handle the case where the type is never.
  • The code should be well-documented and easy to understand.
  • The functions should be generic, allowing them to work with any type T.

Notes

  • Consider using type guards within isType to perform the type checking.
  • The asType function can leverage the as keyword for type assertion, but remember to handle the potential for failed assertions gracefully.
  • The extractType function utilizes conditional types to handle the never case. This is a powerful feature of TypeScript.
  • Think about how to make your code as type-safe as possible. Avoid using any within your utility functions.
  • Focus on creating reusable and well-tested functions.
Loading editor...
typescript