What Is the Difference Between any and unknown in TypeScript?

In TypeScript, both any and unknown represent values of any possible type, but they enforce fundamentally different safety guarantees. The any type acts as an escape hatch from the type checker, allowing any operation, property access, or assignment without compile-time verification. In contrast, the unknown type represents a type-safe counterpart that requires explicit type narrowing or type assertions before any operation can be performed on the value.

Understanding the any Type

The any type completely disables TypeScript's static type analysis for the assigned variable. When a value is typed as any, the compiler assumes that all properties, methods, and operations exist and are valid.

let value: any = "Hello World";

value.foo(); // Compiles without error, fails at runtime
value.length; // Compiles without error
let isNumber: number = value; // Compiles without error, even though value is a string

While any provides maximum flexibility, it eliminates compile-time safety and can introduce runtime errors. It is primarily intended for migrating legacy JavaScript codebases or handling scenarios where typing provides no practical benefit.

Understanding the unknown Type

Introduced in TypeScript 3.0, unknown is the type-safe equivalent of any. A variable of type unknown can hold any value, but the compiler will not allow arbitrary operations or property accesses on it without first verifying its concrete type.

let value: unknown = "Hello World";

// value.foo(); // Error: Object is of type 'unknown'.
// value.length; // Error: Object is of type 'unknown'.
// let isNumber: number = value; // Error: Type 'unknown' is not assignable to type 'number'.

Before interacting with an unknown variable, you must narrow its type using control flow analysis tools such as typeof, instanceof, or custom type guards.

if (typeof value === "string") {
  console.log(value.length); // Valid: narrowed to string
}

Key Differences

Feature any unknown
Accepts any value Yes Yes
Assignable to other types Yes (except never) Only to unknown and any
Direct property access Allowed without checks Disallowed without narrowing
Direct method invocation Allowed without checks Disallowed without narrowing
Type safety level None High

When to Use Each Type

Use unknown as the default choice when dealing with data whose structure is not known ahead of time, such as deserialized JSON, user input, or responses from third-party APIs. This forces callers to perform runtime checks before operating on the data.

Reserve any strictly for temporary migration phases, rapid prototyping, or dynamic edge cases where writing a sound type signature or guard is impractical.