Back to Blog
Lesson 19 of the TypeScript: Typing JavaScript with Confidence course
TypeScriptAugust 6, 20264 min read

Any vs Unknown: Mastering TypeScript Type Safety

Stop using 'any' and start writing safer code. Learn why 'unknown' is the superior choice for handling dynamic data in TypeScript and how to use it properly.

typescripttype-safetybest-practicesunknownany
No parking sign against a gray brick wall, emphasizing traffic regulations.

Previously in this course, we explored Mastering the Typeof Guard in TypeScript for Runtime Safety to handle data at runtime. In this lesson, we shift our focus from narrowing known types to managing data when we have no idea what it is, specifically by replacing the permissive any type with the strict unknown type.

The Problem with 'any'

When you use any, you are effectively telling the TypeScript compiler: "Stop checking this variable, I know what I'm doing." While this might seem convenient, it is the single most common cause of runtime crashes in TypeScript applications.

any disables all type-checking. You can call methods that don't exist, pass variables to functions that expect different shapes, and access properties that aren't there—all without a single warning from your IDE.

TYPESCRIPT
let userData: any = "admin";
userData.toUpperCase(); // Fine
userData.nonExistentMethod(); // No compiler error, but will crash at runtime!

Why 'unknown' is the Better Alternative

Introduced as a type-safe counterpart to any, unknown forces you to perform a check before you can interact with a value. It is the "top type"—anything can be assigned to unknown, but you cannot perform operations on an unknown value until you narrow it down.

Think of unknown as a locked box. You know there is something inside, but you can't touch it until you verify what it is.

Featureanyunknown
Type CheckingDisabledEnabled
Property AccessAllowedDisallowed
Method InvocationAllowedDisallowed
Requires GuardingNoYes

Worked Example: Safely Parsing API Data

In our ongoing Task API project, we often receive raw JSON from fetch. If we don't know the structure, we shouldn't cast it to our Task interface immediately. Instead, we treat it as unknown.

TYPESCRIPT
interface Task {
  id: number;
  title: string;
}

// Imagine this comes from an external, untyped source
const rawResponse: unknown = JSON.parse(CE9178">'{"id": 1, "title": "Finish Lesson"}');

// Attempting this will throw a compile-time error:
// console.log(rawResponse.title); // Error: Object is of type CE9178">'unknown'

// We must narrow the type first
if (typeof rawResponse === CE9178">'object' && rawResponse !== null && CE9178">'title' in rawResponse) {
  // TypeScript now knows CE9178">'rawResponse' has a title property
  const task = rawResponse as Task;
  console.log(task.title);
}

Hands-on Exercise

  1. Create a variable called apiPayload and set its type to unknown.
  2. Assign it an object representing a task: { id: 101, status: 'pending' }.
  3. Try to access apiPayload.id directly. Observe the error.
  4. Use a typeof check or the in operator (as discussed in The In Operator for Object Narrowing in TypeScript) to verify the object structure before logging the id to the console.

Common Pitfalls

  • The "Lazy" Cast: Developers often use as Task immediately after receiving data from an API. This is just as dangerous as any. Always validate the structure (e.g., using a library like Zod or simple in checks) before asserting a type.
  • Assuming Non-Null: Remember that typeof null is 'object'. Always check value !== null when validating if an unknown value is an object.
  • Forgetting Narrowing: If you find yourself writing as repeatedly, you are likely missing an opportunity to use Type Narrowing with Conditionals in TypeScript to handle the logic flow more naturally.

FAQ

Can I assign unknown to other types? Only to any and unknown. You cannot assign unknown to a string or number without explicitly checking the value first.

Is there ever a reason to use any? Very rarely. It is sometimes used as an escape hatch when dealing with poorly typed legacy third-party libraries, but even then, creating a custom .d.ts declaration file is a better long-term strategy.

Does unknown affect performance? No. TypeScript types are erased at compile time. unknown is a tool for the developer and the compiler, not the JavaScript engine.

Recap

  • any is a "blindfold" that disables type safety.
  • unknown is a "guard" that requires explicit validation.
  • Always prefer unknown over any when the shape of the data is uncertain.
  • Narrow your unknown types using typeof, in, or custom type guards before accessing properties.

Up next: We will dive into Generics to make our code more reusable without sacrificing the safety we've worked so hard to build.

Similar Posts