715

TypeScript 3.0 introduces unknown type, according to their wiki:

unknown is now a reserved type name, as it is now a built-in type. Depending on your intended use of unknown, you may want to remove the declaration entirely (favoring the newly introduced unknown type), or rename it to something else.

What is difference between unknown and any? When should we use unknown over any?

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
Jac Mos
  • 7,746
  • 4
  • 15
  • 21
  • 7
    `Anything is assignable to unknown, but unknown isn't assignable to anything but itself` sounds like rhyme – Naren Jul 10 '22 at 19:45
  • 2
    `unknown` and `any` are 2 special types that can hold any value in typescript. However, `Unknown` is recommended over `any` because it offers type checking whenever we try to use the variable. – Amit kumar Jul 29 '22 at 08:17
  • Unknown is what most typed language use (named Object in C#, java or AS3). It's the base type from which all other types inherit, and it behave according to a general rule which says you can't assign a value of a less specific type to a more specific type. Any is more like a permissive hack that disable all typing rules, it's a good rule of thumb to avoid it whenever possible – Vincent Aug 09 '23 at 07:40

11 Answers11

862

You can read more about unknown in the PR or the RC announcement, but the gist of it is:

[..] unknown which is the type-safe counterpart of any. Anything is assignable to unknown, but unknown isn't assignable to anything but itself and any without a type assertion or a control flow based narrowing. Likewise, no operations are permitted on an unknown without first asserting or narrowing to a more specific type.

A few examples:

let vAny: any = 10;          // We can assign anything to any
let vUnknown: unknown =  10; // We can assign anything to unknown just like any 


let s1: string = vAny;     // Any is assignable to anything 
let s2: string = vUnknown; // Invalid; we can't assign vUnknown to any other type (without an explicit assertion)

vAny.method();     // Ok; anything goes with any
vUnknown.method(); // Not ok; we don't know anything about this variable

The suggested usage is:

There are often times where we want to describe the least-capable type in TypeScript. This is useful for APIs that want to signal “this can be any value, so you must perform some type of checking before you use it”. This forces users to safely introspect returned values.

Ilya
  • 143
  • 1
  • 14
Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357
  • 226
    Anyone coming from C# background, `any` is like `dynamic` and `unknown` is like `object`. I like `unknown` as it is just more type safe. Confusing names though. – nawfal Mar 12 '19 at 13:33
  • 3
    I don't know that this is a fair to compare `unknown` and `object` @nawfal although I think I see what you're getting at in terms of the contravariance and covariance (e.g. any object is assignable to type `object` although for `unknown` any object or primitive may be assigned - similarly `unknown` can be assigned to `any` or itself and `object` could be assigned to `dynamic` or itself). On a side note I'm unclear why the TS docs refer to `unknown` as a top type because it doesn't really contain all types ¯\_(ツ)_/¯ – Jordan Jun 13 '19 at 01:35
  • 370
    How I read it: `unknown` is *I don't know*; `any` is *I don't care* – bozdoz Jan 27 '21 at 21:09
  • 38
    More verbosely, `unknown` is *I don't know (yet), thus I have to figure it out*, `any` is *I don't care, thus I don't care* – Loi Nguyen Huynh Dec 23 '21 at 03:25
  • 2
    So with type `unknown`, your code has to identify a type before you can access any members of that type or the TS compiler will complain; with type `any`, the compiler will not complain about accessing a property, even though that property may not exist at runtime? – Suncat2000 Apr 04 '22 at 13:38
  • Unknown is a top type specifically because all other types are assignable to it. In other words, not knowing anything about unknown makes it possible to assign any value to it, because there are no constraints. – portalguy15837 Nov 19 '22 at 18:03
  • This answer doesn't really help. You don't show how unknown is to be used, you just show what we have all encourtered already. – basickarl Jan 23 '23 at 13:25
  • @basickarl A good example I can think of for `unknown` is when handling an API's error response. And then narrowing its type while processing it. – Fanoflix Jul 28 '23 at 09:14
120

they are different in semantics.

unknown is the parent type of all other types. it's a regular type in the type system.

any means "disable the type check". it's a compiler directive.

Zim
  • 1,528
  • 1
  • 10
  • 6
  • 25
    These simple sentences make a lot of sense. – Loi Nguyen Huynh Dec 23 '21 at 03:31
  • 1
    Could you elaborate on "meta programming"? Why did you use it in relation to `any`? – Andru Feb 06 '22 at 11:32
  • 2
    @Andru "meta programming" means the word "any" is not the content being compiled, that's to say, it doesn't tell the compiler what to be compiled. Instead, it configures the process of compilation, that's to say, it tells the compiler how to compile. – Zim Feb 06 '22 at 12:21
73

The difference between unknown and any is described as:

Much like any, any value is assignable to unknown; however, unlike any, you cannot access any properties on values with the type unknown, nor can you call/construct them. Furthermore, values of type unknown can only be assigned to unknown or any.

To answer your question of when should you use unknown over any:

This is useful for APIs that want to signal “this can be any value, so you must perform some type of checking before you use it”. This forces users to safely introspect returned values.

Take a look at the TypeScript 3.0 announcement for examples of type checking a variable of type unknown and a more detailed explanation.

Awad Maharoof
  • 2,260
  • 1
  • 24
  • 36
  • "this can be any value, so you must perform some type of checking before you use it". Let's say I'm writing a reusable function, which takes an argument of type `unknown`, by "you" here you mean me or the ones who consume my function? Who have to do the type check? – Loi Nguyen Huynh Dec 23 '21 at 03:28
53

any type:

The any type represents all possible JS values. Every type is assignable to type any. Therefore the type any is an universal supertype of the type system. The TS compiler will allow any operation on values typed any. For example:

let myVar: any;

myVar[0];
myVar();
myVar.length;
new myVar();

In many occasions this is too lenient of the TS compiler. i.e. it will allow operations which we could have known to be resulting into a runtime error.

unknown type:

The unknown type represents (just like any) all possible JS values. Every type is assignable to type unknown. Therefore the type unknown is another universal supertype of the type system (alongside any). However, the TS compiler won't allow any operation on values typed unknown. Furthermore, the unknown type is only assignable to the type any. An example will clarify this:

let myVar: unknown;

let myVar1: unknown = myVar;   // No error
let myVar2: any = myVar;       // No error
let myVar3: boolean = myVar;   // Type 'unknown' is not assignable to type 'boolean'

// The following operations on myVar all give the error:
// Object is of type 'unknown'
myVar[0];
myVar();
myVar.length;
new myVar();
Willem van der Veen
  • 33,665
  • 16
  • 190
  • 155
52

any, unknown:

  • allow assigning any type

any:

  • allows being assigned to any type
  • allows calling any method

unknown:

  • doesn't allow being assigned to any type
  • doesn't allow calling any method
const a: any = 'a'; // OK
const b: unknown = 'b' // OK

const v1: string = a; // OK
const v2: string = b; // ERROR
const v3: string = b as string; // OK

a.trim() // OK
b.trim() // ERROR
bubbleking
  • 3,329
  • 3
  • 29
  • 49
user1660210
  • 2,306
  • 1
  • 19
  • 16
  • 4
    `doesn't allow to call any method`, this is incorrect (or maybe just hard to understand?). anyway, you can call any method on a value typed as `any`. – MEMark Aug 21 '20 at 12:00
  • 6
    The only answer to show use of `as T`, which will change the type from `unknown` to `T`. Very good. – Craig Hicks Dec 23 '20 at 05:42
  • As I understand now (even using them for some good time), `any` is basically using bare javascript. `unknown` is basically a safer way to deal with stuff you don't know the type. – Henrique Bruno Apr 23 '21 at 21:45
14

I am late to the party but will try to demystify it.

const canBeAnything: any = 100;
const canNotBeAnything: unknown = 100;

// If we try to use a .startsWith() method
canBeAnything.startsWith('10'); // no error
canNotBeAnything.startsWith('10'); // Property 'startsWith' does not exist on type 'unknown'

only way to use the method .startsWith() on unknown is explicitly telling compiler the type, like

(canNotBeAnything as string).startsWith('10'); // Chill down TS compiler, I know what I am doing. 

The latter on doesn't show any compilation error but it throws error during runtime because canNotBeAnything is a number type and we are forcing it to be string

Shankar Regmi
  • 854
  • 1
  • 7
  • 16
13

Unknown

If you write a function that only passes down an input to another function, use unknown. From the perspective of the function: "I don't know, I don't wanna know". There is nothing wrong with using unknown.

E.g.:

function buy(item: unknown): Purchase {
  if (item) {
    return purchase(item);
  } else {
    throw new TypeError('item is missing');
  }
}

Any

If you need to call properties on that value, then any is more suited.

Linting might not like any, suggesting you to be more specific with your input. That way, if you change the interface from isItem to isValid, typescript tells you to update your code.

E.g.:

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
function isItem(item: any): item is Purchase {
  return !!item?.price;
}

Calling properties

function isStuff(item: unknown): item is Stuff {
  return (item as Stuff).it !== undefined;
}
function isStuff(item: any): item is Stuff {
  return item.it !== undefined;
}
camelcaseKeys(item) as unknown as Item;

See user defined guards if you're interested, I brought it in because it's one of the few cases where I need any.

From this blog from ultimatecourses:

Use the any type when there are no other options

It's hard to find good examples for any.

ecoologic
  • 10,202
  • 3
  • 62
  • 66
4

Here's the mental to easily distinguish any from unknown.

What's common

You can assign anything to any and anything to unknown.

let anyVar: any = 'Value';         // OK
anyVar = 3;                        // OK
let unknownVar: unknown = 'Value'; // OK
unknownVar = 3;                    // OK

See the demo

What's different

You can perform any operation on any, but you have to do a type check or type assertion to operate on unknown.

let anyVar: any = 'Value';

anyVar.length // OK
let unknownVar: unknown = 'Value';

unknownVar.length             // NOT OK

(unknownVar as string).length // OK (with type assertion)
if (typeof unknownVar === 'string') {
  unknownVar.length;          // OK (with type check)
}

See the demo

Check also the post "unknown vs any in TypeScript" (I'm the post author).

Dmitri Pavlutin
  • 18,122
  • 8
  • 37
  • 41
  • 1
    I love this answer, not because it adds anything to the older answers, rather because it's the best to take note from. Great writing and summarization just like your articles Dmitri. ;) – aderchox Jun 08 '23 at 16:02
1

The difference is about what you can do with a value of the given type.

Any

When you are given a val: any, the compiler won't (can't) stop you from shooting yourself in the foot.

  • It may be a string, so you can write val.startsWith("a") (and crash with TypeError: 42.startsWith is not a function if val is 42)
  • It may be a function, so you can write val(42) (and crash with TypeError: "foo" is not a function if val is "foo")
  • It may be a number, so you can write val * 2 (and get NaN if it's "foo")
  • It may be a Foo, so you can write val.bar().

Unknown

When you are given a val: unknown, you have to do some type-checking before you can do the above.

  • You can write val.startsWith("a") only after validating that val is a string (typeof(val)==="string")
  • You can write val.bar() only after validating that val is an object that has a method called bar that takes no arguments.
noamtm
  • 12,435
  • 15
  • 71
  • 107
1

In simpler terms,

  • any lets you do anything you want
  • unknown doesn't let you do anything at all without checking the type first.

For example -

let a: any;
let b: unknown;

a.anything() // no error
b.anything() // error 'b' is of type 'unknown'.

any disables all the type-checking Typescript does. While unknown forces you to be super strict with whatever type you are assigning.

0

The accepted answer says "unknown which is the type-safe counterpart of any."

However, as this example shows unknown is its own beast and it sometimes behaves very differently from any:

type Foo = unknown extends string ? true : false // false
type Bar = any extends string ? true : false     // boolean - i.e. both true and false
TrevTheDev
  • 2,616
  • 2
  • 18
  • 36
  • 6
    This answer seems like more of a comment for the accepted answer - not an actual answer. – CodeFinity Mar 09 '22 at 11:39
  • 2
    @CodeFinity It is both - the question is "What is difference between unknown and any?" and my answer provides a key and important difference that's worth understanding. – TrevTheDev Mar 10 '22 at 00:15