Skip to main content

Unknown Type

unknown is the type-safe alternative to any.

The mental model

When you type something as any, you are telling TypeScript to turn off all checks. You can call methods on it, pass it anywhere, and assume it's whatever you want.

When you type something as unknown, you are saying "I don't know what this is yet." TypeScript will aggressively prevent you from doing anything with an unknown value until you perform a type guard to prove what it is.

let unsafe: any = 10;
unsafe.toUpperCase(); // Valid: No compile error, but will crash at runtime

let safe: unknown = 10;
// safe.toUpperCase(); // Error: Object is of type 'unknown'

if (typeof safe === "string") {
safe.toUpperCase(); // Valid, we proved it's a string
}

Where you should use it

  1. API Responses: When you fetch data from an external source, it is truly unknown until you validate it.
  2. catch blocks: In TypeScript 4.4+, caught errors are unknown by default because you could theoretically throw anything in JavaScript, not just Error objects.
try {
throw "Just a string error";
} catch (error: unknown) {
// error.message // Error: object is of type 'unknown'

if (error instanceof Error) {
console.log(error.message); // Valid
} else if (typeof error === "string") {
console.log(error); // Valid
}
}

Forcing a cast from unknown

If you are absolutely certain of the type of an unknown value (e.g., you just validated it using a JSON schema library like Zod), you can use the as keyword to cast it without traditional type guards.

const response: unknown = getExternalData();
const user = response as User; // We are telling TS to trust us

Always prefer unknown over any. It forces you to write defensive code and validate data before operating on it.