TypeScript Never and Unknown

TypeScript provides two special types — never and unknown — that handle edge cases no basic type can express. unknown represents a value whose type is not yet known. never represents a value that can never exist or a code path that can never finish normally. Both exist to make TypeScript safer in tricky situations.

The unknown Type

The unknown type is the safe version of any. Both accept any value, but any lets you do anything with that value immediately. unknown forces a type check first.

ANY vs UNKNOWN
──────────────────────────────────────────────────────
  let a: any     = "Hello";
  a.toUpperCase(); // Works — TypeScript trusts you blindly

  let u: unknown = "Hello";
  u.toUpperCase(); // Error! TypeScript says: prove it's a string first
──────────────────────────────────────────────────────

Assigning to unknown

let value: unknown;

value = 42;           // OK
value = "text";       // OK
value = true;         // OK
value = [1, 2, 3];    // OK
value = { name: "Pooja" }; // OK

// unknown cannot be used directly without type checking
let text: string = value; // Error: Type 'unknown' is not assignable to type 'string'

Using unknown Safely

function printValue(val: unknown): void {
    if (typeof val === "string") {
        console.log(val.toUpperCase()); // Safe — val is string here
    } else if (typeof val === "number") {
        console.log(val.toFixed(2));    // Safe — val is number here
    } else if (Array.isArray(val)) {
        console.log(val.length);        // Safe — val is array here
    } else {
        console.log("Unknown type received");
    }
}

printValue("hello");   // HELLO
printValue(3.14159);   // 3.14
printValue([1, 2, 3]); // 3

Real Use of unknown — API Responses

// When fetching data from an API, the response type is not guaranteed
async function fetchData(url: string): Promise {
    let response = await fetch(url);
    return response.json();   // could be anything
}

async function main() {
    let data: unknown = await fetchData("https://api.example.com/user");

    // Must check before using
    if (typeof data === "object" && data !== null && "name" in data) {
        let user = data as { name: string };
        console.log(user.name);
    }
}

The never Type

The never type represents a value that can never occur. TypeScript uses it in two situations: functions that never return (they throw an error or run forever), and impossible type branches in type guards.

NEVER IN CODE FLOW
─────────────────────────────────────────────────
Function A → returns string      (returns something)
Function B → returns void        (returns nothing/undefined)
Function C → returns never       (never returns at all — throws or loops forever)
─────────────────────────────────────────────────

never in Functions That Throw

function throwError(message: string): never {
    throw new Error(message);
    // Nothing after this runs — function never returns
}

function crashApp(): never {
    throw new Error("Critical failure — app stopped.");
}

// Using in code
function divide(a: number, b: number): number {
    if (b === 0) {
        throwError("Cannot divide by zero"); // never — stops here
    }
    return a / b;  // TypeScript knows this line only runs if b !== 0
}

console.log(divide(10, 2)); // 5
// divide(10, 0) — throws error

never in Infinite Loops

function keepListening(): never {
    while (true) {
        // process events forever
        // never returns — hence return type is never
    }
}

never as an Exhaustiveness Check

The most powerful use of never is catching missing cases in a switch statement. When TypeScript narrows a type down to nothing, the remaining type becomes never. Assigning it to a variable typed as never causes an error if any case was missed.

type Status = "active" | "inactive" | "suspended";

function handleStatus(status: Status): string {
    switch (status) {
        case "active":
            return "Account is active";
        case "inactive":
            return "Account is inactive";
        case "suspended":
            return "Account is suspended";
        default:
            // If all cases are covered, TypeScript knows status is never here
            const _exhaustive: never = status;
            return _exhaustive;
    }
}

// Now add a new status without updating the switch:
// type Status = "active" | "inactive" | "suspended" | "banned";
// TypeScript immediately shows an error at the default line
// because "banned" is not handled — it is not assignable to never

Diagram: Where never Appears Automatically

function classify(x: string | number): string {
    if (typeof x === "string") {
        // x is string here
        return x.toUpperCase();
    }
    if (typeof x === "number") {
        // x is number here
        return x.toFixed(2);
    }
    // At this point TypeScript sees: all types are exhausted
    // x is inferred as never here
    // Nothing can reach this line
}

unknown vs any vs never

TypeMeaningRequires Type Check?When to Use
anyCould be anything — TypeScript ignores typeNoQuick prototypes (avoid in production)
unknownCould be anything — must check before usingYesAPI responses, external data, user input
neverCannot exist — function never returnsN/AError functions, infinite loops, exhaustiveness checks

Practical Example: Safe JSON Parser

function parseJSON(jsonString: string): unknown {
    try {
        return JSON.parse(jsonString);
    } catch {
        throwParseError(jsonString);
    }
}

function throwParseError(input: string): never {
    throw new Error(`Failed to parse: ${input}`);
}

// Caller must check the type before using the result
let result = parseJSON('{"name": "Aditya", "age": 22}');

if (typeof result === "object" && result !== null) {
    let user = result as { name: string; age: number };
    console.log(user.name); // Aditya
    console.log(user.age);  // 22
}

Key Takeaways

TypeKey Rule
unknownAccept anything, but check type before use — safer than any
neverUsed for functions that never return and for exhaustiveness checks
Both togetherHelp write code that handles every possible case with zero guessing

Leave a Comment

Your email address will not be published. Required fields are marked *