- Published on
TypeScript Comparing 'any' and 'unknown' Types
- Authors

- Name
- Yinhuan Yuan
Introduction
TypeScript, a statically typed superset of JavaScript, has gained immense popularity due to its ability to catch errors at compile-time and provide better tooling support. Two of its type annotations, any and unknown, are often misunderstood or used interchangeably. In this blog post, we'll dive deep into these types, explore their differences, and discuss when to use each.
The 'any' Type
The any type is TypeScript's escape hatch from its type system. It allows you to opt-out of type checking for a particular value.
Characteristics of 'any':
- No Type Checking: Variables of type
anycan hold values of any type. - Allows All Operations: You can perform any operation on an
anytype without type checks. - Propagates through Operations: Using an
anyvalue in an operation results in ananytype.
Example of 'any':
let anyValue: any = 10
anyValue = 'Hello' // OK
anyValue = true // OK
let num: number = anyValue // OK (but potentially unsafe)
console.log(anyValue.nonExistentMethod()) // No compile-time error
The 'unknown' Type
Introduced in TypeScript 3.0, the unknown type is a type-safe counterpart of any.
Characteristics of 'unknown':
- Type-safe: Variables of type
unknowncan hold any value, but TypeScript won't allow operations on anunknownwithout type checks. - Requires Type Checking: You must narrow the type (through type guards or assertions) before performing operations.
- Doesn't Propagate: Using an
unknownvalue in an operation doesn't implicitly spread theunknowntype.
Example of 'unknown':
let unknownValue: unknown = 10
unknownValue = 'Hello' // OK
unknownValue = true // OK
let num: number = unknownValue // Error: Type 'unknown' is not assignable to type 'number'
if (typeof unknownValue === 'number') {
let num: number = unknownValue // OK
}
console.log(unknownValue.toString()) // Error: Object is of type 'unknown'
Comparing 'any' and 'unknown'
Type Safety:
any: Bypasses all type checks.unknown: Enforces type checks, making it much safer.
Assignability:
any: Can be assigned to any other type.unknown: Can only be assigned tounknownorany.
Operations:
any: Allows all operations without checks.unknown: Requires type narrowing before operations.
Best Practices:
- Use
anywhen you need to opt-out of type checking entirely (e.g., when working with dynamic content or during migration from JavaScript). - Use
unknownwhen you want to accept any value but ensure type-safe operations later.
- Use
When to Use 'unknown'
- API Responses: When working with responses from APIs where the structure isn't known at compile-time.
async function fetchData(): Promise<unknown> {
const response = await fetch('https://api.example.com/data')
return response.json()
}
const data = await fetchData()
if (typeof data === 'object' && data !== null && 'name' in data) {
console.log(data.name) // TypeScript knows 'data' has a 'name' property
}
- Type Assertions: When you need to work with a value whose type you know but TypeScript doesn't.
function processValue(value: unknown) {
if (typeof value === 'string') {
console.log(value.toUpperCase())
} else if (Array.isArray(value)) {
console.log(value.length)
}
}
Conclusion
While any provides flexibility, it comes at the cost of type safety. The unknown type offers a balance between flexibility and safety, encouraging developers to think about types and perform necessary checks.
As a best practice:
- Avoid
anyunless absolutely necessary. - Use
unknownwhen you need to accept any value but want to maintain type safety. - Always narrow
unknowntypes before performing operations on them.
By understanding and correctly using any and unknown, you can write more robust and maintainable TypeScript code, leveraging the full power of TypeScript's type system while still handling dynamic or unknown data when needed.