Understanding any and unknown Types
Learn how unknown gives you safety where any gives you nothing and how to work with both using guards, assertions, and conversions.
When TypeScript doesn’t know what something is, it sometimes gives up and infers the type any
. This might happen when you’re consuming dynamic data, skipping type annotations, or interacting with poorly typed libraries.
At first, any
feels helpful—no more compiler complaints. But here’s the hard truth: any
turns off TypeScript’s entire type checking system.
let value: any = "hello";value(); // no error at compile time — runtime crashvalue.trim(); // worksvalue.toFixed(); // compiles — but crashes at runtimeconsole.log(`Value: ${value}`);
Explanation:
Line 1: The variable is typed as
any
, so the compiler stops validating what it really is.Line 2: We call the value like a function—TypeScript allows it, but it crashes at runtime.
Line 3: This one works, because the value is actually a string.
Line 4: This compiles fine but
.toFixed()
only exists on numbers, not strings. This is another runtime trap.
any
is effectively a license to ignore correctness. The code compiles, but any mistake becomes a runtime bug waiting to happen.
Meet unknown
: The safer option
unknown
solves the same problem as any
—but it refuses to abandon safety. It lets us assign any value to a variable, but we can’t use it until we prove what it is.
let input: unknown = "Ada";input.trim(); // Error!console.log(`Input is: ${input}`);
Explanation:
Line 1: We assign a string to a variable of type
unknown
.Line 2: Even though it’s a string, we can’t use string methods without first checking or asserting the type.
This makes unknown
perfect for handling uncertain or external data. Instead of turning off the compiler, we delay the decision and force ourselves to earn type confidence—TypeScript won’t let us proceed until we prove what the value really is.
Think about when we’re reading from localStorage
, calling an API, or accessing a form field, we might receive data with an unknown shape. That’s where the unknown
type comes in—it tells TypeScript, “we don’t trust this yet.” We’ll have to check it before using it.
To work with unknown
, we use runtime type guards—they let us confirm what a value is before we use it.