TypeScript Special Types

Understanding any, unknown, and never types

⚡ Special Types in TypeScript

TypeScript has three special types: any (disables type checking), unknown (type-safe any), and never (represents values that never occur). These handle edge cases where standard types don't fit perfectly.


let flexible: any = "anything";
let safe: unknown = "needs checking";
function error(): never {
    throw new Error("Never returns");
}
                                    

Three Special Types

🔓

any

Disables type checking

let data: any = 5;
data = "text"; // OK
data = true;   // OK
🔒

unknown

Type-safe version of any

let value: unknown = 5;
// Must check type first
if (typeof value === "number") {
    console.log(value + 1);
}
🚫

never

Represents impossible values

function fail(): never {
    throw new Error("Failed");
}

🔹 The any Type

The any type disables type checking - use sparingly:

// any allows anything
let value: any = 10;
value = "Hello";      // OK
value = true;         // OK
value = [1, 2, 3];    // OK

// No type checking on operations
let result: any = "5";
console.log(result * 2);  // No error, but outputs: NaN

// Use case: Working with dynamic data
let userInput: any = getUserInput(); // From external source

Output:

NaN

⚠️ Warning:

Using any defeats the purpose of TypeScript. Only use it when absolutely necessary!

🔹 The unknown Type

unknown is safer than any - requires type checking before use:

// unknown requires type checking
let userInput: unknown = "Hello";

// ❌ Error: Can't use directly
// console.log(userInput.toUpperCase());

// ✅ Correct: Check type first
if (typeof userInput === "string") {
    console.log(userInput.toUpperCase());  // OK
}

// Another example
let data: unknown = 42;

if (typeof data === "number") {
    console.log(data + 10);  // Output: 52
}

Output:

HELLO

52

🔹 The never Type

never represents values that never occur:

// Function that never returns
function throwError(message: string): never {
    throw new Error(message);
}

// Infinite loop never returns
function infiniteLoop(): never {
    while (true) {
        console.log("Running forever...");
    }
}

// Practical use: Exhaustive checking
type Shape = "circle" | "square";

function getArea(shape: Shape): number {
    switch (shape) {
        case "circle":
            return 3.14;
        case "square":
            return 4;
        default:
            // This should never happen
            const exhaustive: never = shape;
            throw new Error(`Unhandled shape: ${exhaustive}`);
    }
}

🔹 Comparing Special Types

Understanding when to use each type:

any vs unknown:

// any: No safety
let anyValue: any = "text";
anyValue.toUpperCase();  // Works
anyValue.nonExistent();  // No error (but fails at runtime!)

// unknown: Type-safe
let unknownValue: unknown = "text";
// unknownValue.toUpperCase();  // Error: Must check type first

if (typeof unknownValue === "string") {
    unknownValue.toUpperCase();  // OK
}

📊 Quick Comparison:

  • any: Opt-out of type checking (use rarely)
  • unknown: Type-safe any (preferred over any)
  • never: Functions that never return or impossible values

🔹 Practical Examples

Real-world usage of special types:

Example 1: API Response (unknown)

// Handling API data safely
function processAPIResponse(response: unknown) {
    if (typeof response === "object" && response !== null) {
        console.log("Valid object received");
        // Further processing...
    } else {
        console.log("Invalid response");
    }
}

processAPIResponse({ name: "Alice" });  // Valid object received
processAPIResponse("invalid");          // Invalid response

Example 2: Error Handler (never)

// Utility function that always throws
function assertNever(value: never): never {
    throw new Error(`Unexpected value: ${value}`);
}

type Status = "success" | "error";

function handleStatus(status: Status) {
    switch (status) {
        case "success":
            console.log("Success!");
            break;
        case "error":
            console.log("Error!");
            break;
        default:
            assertNever(status); // Ensures all cases handled
    }
}

🔹 Best Practices

✅ Do:

  • Use unknown instead of any when possible
  • Use never for functions that throw errors
  • Always check types before using unknown values
  • Use never for exhaustive type checking

❌ Don't:

  • Use any unless absolutely necessary
  • Use unknown without type guards
  • Assign values to never type variables
  • Ignore TypeScript errors by using any

🧠 Test Your Knowledge

Which type is safer to use than 'any'?