Suggest an editImprove this articleRefine the answer for “Differences between any and unknown in TypeScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`any` and `unknown`** both accept any value in TypeScript, but `unknown` is type-safe. - `any` disables type checking entirely - `unknown` requires type narrowing before use (via `typeof`, `instanceof`, or type guards) ```typescript const x: unknown = getData(); if (typeof x === 'string') x.toUpperCase(); // OK after narrowing ``` **Key:** use `unknown` for external data by default; `any` only as a deliberate escape hatch.Shown above the full answer for quick recall.Answer (EN)Image**`any` and `unknown`** are both types that accept any value in TypeScript, but only `unknown` forces you to verify the type before using it. ## Theory ### TL;DR - `any` is a blank check: call any method, access any property, no questions asked - `unknown` is a locked box: you must prove what is inside before TypeScript lets you touch it - `any` disables type checking; `unknown` keeps it on and demands type guards - Default for "I don't know the type yet": `unknown`. Use `any` only when deliberately bypassing TypeScript ### Quick example ```typescript function process(value: any) { value.toUpperCase(); // No error - but crashes if value is a number } function processSafe(value: unknown) { value.toUpperCase(); // Error: Object is of type 'unknown' if (typeof value === 'string') { value.toUpperCase(); // OK - type narrowed to string } } ``` `processSafe` forces you to check first. `process` trusts you blindly, and that trust can crash at runtime. ### Key difference `any` tells TypeScript: "stop checking this value entirely." You can call any method, assign it anywhere, pass it to anything. `unknown` says: "I don't know what this is." You can store it and pass it around, but you cannot call methods or read properties until you prove the type with a type guard. One disables the type system; the other works with it. ### When to use - `unknown`: API responses, `JSON.parse()` results, error objects in `catch` blocks, parameters from external input - `any`: integrating untyped third-party libraries, temporary workarounds during migration (document it when you do) - Neither: if you can define the actual type, always do that ### Comparison table | Aspect | `any` | `unknown` | |---|---|---| | Type checking | Disabled | Enabled | | Call methods / access properties | Yes, no errors | No, error until narrowed | | Assign to other typed variables | Yes, freely | No, requires type guard | | Catches mistakes at compile time | No | Yes | | Requires type guards | No | Yes | | When to use | Deliberate escape hatch | Default for unknown types | ### How the compiler handles this TypeScript treats `any` as an opt-out marker: wherever it appears, the compiler skips all type validation for that value in both directions. `unknown` is the opposite - it accepts any value but blocks access to it until you narrow the type. At runtime both are erased to plain JavaScript, so there is zero performance difference between them. ### Common mistakes **Mistake 1: reaching for `any` when you mean "I don't know the type yet"** ```typescript // Wrong function handleData(data: any) { return data.value * 2; // Crashes silently if data is a string } // Correct function handleData(data: unknown) { if (typeof data === 'object' && data !== null && 'value' in data) { const val = data.value; if (typeof val === 'number') return val * 2; } throw new Error('Invalid data structure'); } ``` **Mistake 2: letting `any` spread through function signatures** ```typescript // Wrong - any in, any out, no type checking anywhere function process(input: any): any { return input.transform(); } // Correct - narrow at the boundary, return a concrete type function process(input: unknown): string { if (typeof input === 'string') return input.toUpperCase(); throw new Error('Expected string'); } ``` **Mistake 3: forgetting that `catch` errors are `unknown` in TypeScript 4.0+** ```typescript // Wrong try { doSomething(); } catch (e) { console.log(e.message); // Error: e is of type unknown } // Correct try { doSomething(); } catch (e) { if (e instanceof Error) { console.log(e.message); // Safe } } ``` **Mistake 4: using `any` in object properties as a shortcut** ```typescript // Wrong - the entire property tree becomes untyped interface Config { settings: any; } // Better - keys are strings, values must be narrowed before use interface Config { settings: Record<string, unknown>; } ``` I replaced every `any` with `unknown` across one codebase and TypeScript surfaced three bugs in the first hour that had been hiding in production for months. ### Real-world usage - Express: request body is `unknown` until validated by middleware - `JSON.parse()`: standard lib returns `any`, but wrapping results in `unknown` is safer in practice - Redux: action payloads often typed as `unknown`, narrowed via discriminated unions inside reducers - React event handlers: `event.target` must be narrowed before accessing specific properties - Zod / io-ts: both accept `unknown` input and return a typed result after validation ### Follow-up questions **Q:** Can you assign `unknown` to `any` and vice versa? **A:** Yes to both. `any` accepts everything, and `unknown` also accepts any value on assignment. But you cannot assign `unknown` to a concrete type like `string` without a type guard first. **Q:** What is the difference between `unknown` and a generic type parameter `<T>`? **A:** `unknown` means "some type, I don't know which - prove it before use." A generic `<T>` means "some specific type the caller decides." Generics preserve type information through the call; `unknown` drops it until you narrow. **Q:** What changed in TypeScript 4.0 regarding these types? **A:** The `catch` clause variable became `unknown` by default with `useUnknownInCatchVariables`, enabled automatically in strict mode from TypeScript 4.4. Before that, caught errors were `any`, so code without guards in `catch` blocks used to compile cleanly. **Q:** When would you use `unknown` in a generic constraint instead of a type parameter? **A:** When you want to force the caller to supply a type guard. `function validate<T>(value: unknown, guard: (v: unknown) => v is T): T` is safer than `function validate<T>(value: T): T` because it explicitly handles unknown input and requires a guard to produce a typed result. ## Examples ### API response handling with a type guard ```typescript // Using any - no safety at all async function fetchUser(id: string): Promise<any> { const response = await fetch(`/api/users/${id}`); return response.json(); } const user = await fetchUser('123'); console.log(user.email); // No TypeScript error, but could be undefined // Using unknown - safe async function fetchUserSafe(id: string): Promise<unknown> { const response = await fetch(`/api/users/${id}`); return response.json(); } function isUser(val: unknown): val is { id: string; email: string } { return ( typeof val === 'object' && val !== null && 'id' in val && 'email' in val && typeof (val as Record<string, unknown>).id === 'string' && typeof (val as Record<string, unknown>).email === 'string' ); } const data = await fetchUserSafe('123'); if (isUser(data)) { console.log(data.email); // Fully type-safe } ``` The type guard runs once and gives you a typed value everywhere you need it. That is a better trade-off than skipping the check entirely. ### `any` bypasses generic constraints; `unknown` does not ```typescript function processArray<T extends string>(arr: T[]): void { arr.forEach(item => console.log(item.toUpperCase())); } const anyValue: any = [1, 2, 3]; processArray(anyValue); // No TypeScript error - crashes at runtime const unknownValue: unknown = [1, 2, 3]; processArray(unknownValue); // TypeScript error - caught before runtime ``` `any` passes through generic constraints without a word. `unknown` does not. This is one of the sharper edges of `any` in shared or library code.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.