ComparisonComparisons

any vs unknown

any turns off type checking and allows anything, while unknown also accepts any value but requires a type check before you can use it.

On this page

Side-by-side comparison

#
  • Accepts any value

    any
    Yes
  • Use without a type check

    any
    Yes, the compiler raises no objection
    unknown
    No, you must narrow the type first
  • Calling any method

    any
    Allowed, even a misspelled one
    unknown
    Error: Object is of type 'unknown'
  • Assigning to another type without a check

    any
    Allowed
    unknown
    Blocked
  • Where the error surfaces

    any
    Only once the program is running
    unknown
    Already at compile time
  • Typical use

    any
    Migrating from JavaScript, untyped libraries
    unknown
    Data from an API, JSON.parse(), catch (error)

Example

#
TypeScript
function describeAny(value: any): string {
  return value.toUpperCase()
}

function describeUnknown(value: unknown): string {
  if (typeof value === 'string') return value.toUpperCase()
  return 'unknown type'
}

console.log(describeAny('html'))
console.log(describeUnknown('css'))
console.log(describeUnknown(42))
Result
HTML
CSS
unknown type

Definition and usage

#

Both types accept a value of any kind: you can assign a string, a number, an object, or the result of JSON.parse() to an any or unknown variable. In both cases the compiler has no idea up front what the value actually is.

The difference is in what you’re allowed to do next. With an any value you can call any method right away and pass it anywhere, with no check at all, because the compiler stops watching types. With an unknown value you can’t do anything until you narrow the type with typeof, instanceof, Array.isArray(), or your own type guard. Only after such a check does the compiler expose the methods that belong to the recognized type.

any is a trapdoor that switches TypeScript off wherever you use it, and it’s easy to let a bug slip through it into the running program. unknown gives you the same flexibility when accepting data, but forces you to check it, so for data from outside (an API, JSON.parse(), localStorage) choose unknown. Leave any as a temporary fix while migrating from JavaScript.

Syntax

#
Syntax
let value: any
let other: unknown

More examples

#
any doesn’t protect you from a runtime error
TypeScript
const broken: any = { user: null }

try {
  console.log(broken.user.name)
} catch (error) {
  console.log('Runtime error, the compiler flagged nothing')
}
Result
Runtime error, the compiler flagged nothing
unknown blocks use without a check
TypeScript
const input: unknown = JSON.parse('{"level":7}')
console.log(input.level)
// Error: 'input' is of type 'unknown'.

Good practices

#
  • Turn on the noImplicitAny option, so the compiler doesn’t silently accept any wherever you didn’t give a type.
  • The error in catch (error) has the type unknown. Check error instanceof Error before you read error.message.
  • If you migrate code from any to unknown, the compiler itself will point out every place that needs a type check.

Related entries

#

Spotted a mistake or missing an example? Write to us.