DEV Community

Cover image for TypeScript `unknown` vs `any`: Understanding the Key Differences
ZeeshanAli-0704
ZeeshanAli-0704

Posted on

TypeScript `unknown` vs `any`: Understanding the Key Differences

TypeScript unknown vs any: Understanding the Key Differences

In TypeScript, both unknown and any represent values whose types are not known at compile time. At first glance, they may look similar, but their behavior and impact on type safety are very different.

Choosing the right one can make the difference between safe, maintainable code and a codebase full of runtime surprises.

This blog breaks down the differences, with examples, best practices, and a summary table for quick reference.


Key Differences Between unknown and any

1. Type Safety

  • any: Completely disables type checking. You can perform any operation on it, even invalid ones, and the compiler won’t complain.
  • unknown: Type-safe alternative. You must narrow or assert the type before using it.
let valueAny: any;
let valueUnknown: unknown;

valueAny = "Hello";
console.log(valueAny.toUpperCase()); // ✅ Compiles, may fail at runtime

valueUnknown = "Hello";
console.log(valueUnknown.toUpperCase()); // ❌ Error: must narrow first
Enter fullscreen mode Exit fullscreen mode

2. Usage Restrictions

  • any: Assignable to any type and allows any operation.
  • unknown: Requires explicit type checks or assertions.
let valueAny: any = "Hello";
let str: string = valueAny; // ✅ Works, but unsafe
valueAny.nonExistentMethod(); // ✅ Compiles, 💥 runtime error

let valueUnknown: unknown = "Hello";
// ❌ let str2: string = valueUnknown;
if (typeof valueUnknown === "string") {
  console.log(valueUnknown.toUpperCase()); // ✅ Safe
}
Enter fullscreen mode Exit fullscreen mode

3. Assignment Rules

  • any: Two-way street—assignable to and from anything.
  • unknown: Anything can be assigned to unknown, but unknown itself can only be assigned to any or unknown (unless narrowed).
let valueAny: any;
let valueUnknown: unknown;

valueAny = 42;
let num1: number = valueAny; // ✅ Works

valueUnknown = 42;
// ❌ let num2: number = valueUnknown;

let anyVar: any = valueUnknown;   // ✅ Allowed
let unknownVar: unknown = valueAny; // ✅ Allowed
Enter fullscreen mode Exit fullscreen mode

4. Use Case Philosophy

  • any:

    • Bypasses type system
    • Common in JavaScript → TypeScript migrations
    • Useful for quick prototyping or working with libraries without type definitions
  • unknown:

    • Forces explicit checks
    • Ideal for handling API responses, user input, or external data
    • Safer in modern TypeScript codebases
// API response - unsafe
function fetchData(): any {
  return { name: "Alice", age: 25 };
}
let dataAny = fetchData();
console.log(dataAny.name.toUpperCase()); // ❌ Risky if 'name' isn't a string

// API response - safe
function fetchDataSafe(): unknown {
  return { name: "Alice", age: 25 };
}
let dataUnknown = fetchDataSafe();
if (typeof dataUnknown === "object" && dataUnknown !== null && "name" in dataUnknown) {
  console.log((dataUnknown as { name: string }).name.toUpperCase()); // ✅ Safe
}
Enter fullscreen mode Exit fullscreen mode

5. Error-Prone vs. Safe

  • any: Prone to runtime crashes.
  • unknown: Compiler enforces safety.
let valueAny: any = 42;
valueAny.toUpperCase(); // ❌ Compiles, 💥 runtime error

let valueUnknown: unknown = 42;
// ❌ valueUnknown.toUpperCase(); (compile-time error, safe)
Enter fullscreen mode Exit fullscreen mode

Best Practices

  • 🚫 Avoid any whenever possible – it weakens TypeScript’s core benefit.
  • Use unknown for dynamic data (APIs, JSON, user input).
  • 🔍 Narrow unknown with type guards before use.
function isString(value: unknown): value is string {
  return typeof value === "string";
}

let input: unknown = "Hello";
if (isString(input)) {
  console.log(input.toUpperCase()); // ✅ Safe
}
Enter fullscreen mode Exit fullscreen mode

Summary Table

Feature any unknown
Type Safety ❌ None, disables type checking ✅ Enforces checks before use
Operations Allowed Any operation Only after narrowing
Assignment Assignable to/from anything Assignable to any/unknown only
Use Case Legacy code, migration, quick hacks Safe handling of external data
Runtime Risk High Low (with checks)

Conclusion

  • any: A double-edged sword. Convenient, but dangerous if overused. Best kept for legacy migration or quick fixes.
  • unknown: The safer, modern alternative. It lets you handle dynamic values without sacrificing type safety.

👉 Rule of Thumb:

  • Reach for unknown in modern TypeScript projects.
  • Use any only when you absolutely must bypass the type system.

By preferring unknown over any, you’ll write safer, more predictable, and maintainable TypeScript code.


More Details

Check out the full code of this article on All About Typescript.

Get all articles related to system design:

Hashtag: #SystemDesignWithZeeshanAli

GitHub Repository: SystemDesignWithZeeshanAli

Top comments (0)