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:
-
isType<T>(value: unknown): value is T: A type predicate function that checks if a givenunknownvalue is of a specific typeT. It should returntrueif the value is of typeTandfalseotherwise. Crucially, it should narrow the type ofvaluetoTwithin any code block where it returnstrue. -
asType<T>(value: unknown): T | undefined: A function that attempts to cast anunknownvalue to a specific typeT. If the value is not of typeT, it should returnundefined. This function should not throw an error; instead, it should gracefully handle the case where the cast fails. -
extractType<T>(value: unknown): T extends never ? never : T: A function that extracts the type of a value if it is known, otherwise returnsnever. This is useful for inferring types fromunknownvalues.
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
isTypefunction must be a type predicate. - The
asTypefunction must not throw errors. It should returnundefinedif the cast fails. - The
extractTypefunction should correctly handle the case where the type isnever. - 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
isTypeto perform the type checking. - The
asTypefunction can leverage theaskeyword for type assertion, but remember to handle the potential for failed assertions gracefully. - The
extractTypefunction utilizes conditional types to handle thenevercase. This is a powerful feature of TypeScript. - Think about how to make your code as type-safe as possible. Avoid using
anywithin your utility functions. - Focus on creating reusable and well-tested functions.