The unknown type in TypeScript is a safe, flexible way to handle variables with uncertain types. Unlike any, which allows any kind of operations without restriction, unknown provides a type-safe alternative that requires type-checking before use. This tutorial will cover the basics of the unknown, walk through detailed examples, and show you when and how to use it effectively.
TypeScript’s unknown type is a safer alternative to any, allowing you to work with dynamic data without sacrificing type safety. It encourages type-checking and validation, making your code more reliable and reducing potential runtime errors. This tutorial will explain how to use unknown effectively, how it differs from any, and provide practical examples to demonstrate its value.
In TypeScript, the unknown type represents a variable whose type is not known at the time of declaration. Unlike any, the unknown type requires type-checking before you can perform operations on the variable, making it a safer choice for handling uncertain data.
let data: unknown;
data = "Hello, TypeScript!";
data = 42;
data = { name: "Alice" };
Here:
unknown, allowing it to hold any value.data, but you must validate its type before using it in a type-specific way.unknownWith unknown, TypeScript enforces type-checking before allowing certain operations, encouraging safer coding practices. You can use typeof or custom type assertions to check the type.
typeoflet value: unknown = "Hello, World!";
if (typeof value === "string") {
console.log(value.toUpperCase()); // Safe to use as a string
}
In this example:
value is declared as unknown, so we must check if it’s a string before calling toUpperCase().toUpperCase() unless the type is confirmed.Here are some scenarios where unknown can be used effectively.
function processInput(input: unknown) {
if (typeof input === "string") {
console.log(`String input: ${input.toUpperCase()}`);
} else if (typeof input === "number") {
console.log(`Number input: ${input.toFixed(2)}`);
} else {
console.log("Unknown input type");
}
}
processInput("TypeScript"); // Output: String input: TYPESCRIPT
processInput(3.14159); // Output: Number input: 3.14
In this example:
processInput function accepts input of type unknown.any and unknownWhile any and unknown might seem similar, they behave very differently in TypeScript. Here’s a comparison:
|
Feature |
|
|
|
Type Safety |
No type safety (any operation is allowed) |
Enforces type-checking before usage |
|
Flexibility |
Maximum flexibility; allows all operations |
Allows flexible assignment, restricts usage |
|
Ideal Use Cases |
Legacy code, third-party libraries |
Handling uncertain or dynamic data safely |
|
Type Checking Required |
No |
Yes |
Using unknown encourages you to validate the type, whereas any permits unchecked operations, which can lead to runtime errors.
When working with API data where the response structure may vary, using unknown ensures that your code handles different types safely.
function handleApiResponse(response: unknown) {
if (typeof response === "object" && response !== null) {
if ("message" in response) {
console.log("Message:", (response as { message: string }).message);
} else {
console.log("Response does not contain a message");
}
} else {
console.log("Unexpected response type");
}
}
handleApiResponse({ message: "Hello, World!" }); // Output: Message: Hello, World!
handleApiResponse("Invalid Response"); // Output: Unexpected response type
In this example:
handleApiResponse function accepts response of type unknown.object and if it has a message property, ensuring safe handling of dynamic data.When processing user-defined data where the input type is uncertain, unknown helps enforce type-checking.
function printValue(value: unknown) {
if (Array.isArray(value)) {
console.log("Array:", value.join(", "));
} else if (typeof value === "string") {
console.log("String:", value);
} else if (typeof value === "number") {
console.log("Number:", value.toFixed(2));
} else {
console.log("Unknown type");
}
}
printValue([1, 2, 3]); // Output: Array: 1, 2, 3
printValue("Hello World"); // Output: String: Hello World
printValue(42.5678); // Output: Number: 42.57
In this example:
printValue function uses unknown to accept any input and applies different logic depending on the type.typeof, instanceof, or custom type guards before performing type-specific operations.
function handleInput(input: unknown) {
if (typeof input === "number") {
console.log("Number:", input.toFixed(2));
}
}
let data: unknown = "Hello";
let message: string = data as string; // Type assertion
unknown type provides flexibility while enforcing type-checking, making it a safer alternative to any.typeof, instanceof, or custom type guards is essential when working with unknown.unknown allows dynamic assignment without sacrificing control, making it ideal for handling uncertain data structures.unknown type is particularly useful for dynamic API responses, user-defined data, and input validation.any in favor of unknown for handling uncertain data, as it promotes safer, more reliable code.The unknown type in TypeScript is a flexible yet safe way to handle variables when the type isn’t immediately known. It encourages type-checking, making your code more predictable and less prone to runtime errors. In this tutorial, we explored the difference between unknown and any, detailed examples, and best practices for using unknown effectively. By understanding and applying unknown properly, you can handle uncertain data in TypeScript with confidence and reliability.