Skip to content
Theory · Primitive and special types · lesson 3 of 8

The any type

At customs some parcels carry a stamp that says "do not inspect". The inspector does not open such a box or compare it with its declaration: whatever is inside, the parcel crosses the border. That is convenient, but if the box holds something unexpected, it comes out only inside the country, when someone opens it.

In TypeScript this stamp is called any. Let's compare two programs. In the first one the variable has an honest declaration:

TypeScript
const amount: number = 42;
console.log(amount.toUpperCase()); // ✗
TEXT
error TS2339: Property 'toUpperCase' does not exist on type 'number'.

tsc sees that a number has no toUpperCase method and reports the error before the program runs. Now let's put the stamp on the same parcel:

TypeScript
const amount: any = 42;
console.log(amount.toUpperCase()); // ✗
TEXT
TypeError: amount.toUpperCase is not a function

tsc stays silent, and the program crashes when it runs. The mistake has not gone anywhere: it moved from the check to the moment the program is already running for a user.

any turns the check off

The type any means "anything may be here, do not check it". For such a value the compiler allows everything:

  • call any method: amount.toUpperCase();
  • read any property, even one that does not exist: amount.size;
  • put the value into a variable of any type: const text: string = amount;
  • assign anything to it: a number, a string, an object.

tsc checks the rest of the program as usual. The stamp is on this one parcel only.

Where any comes from

Strict mode catches only an implicit any: as you remember from the previous theme, tsc rejects a parameter without a type. An any written on purpose or received from someone else's code gets past strict mode.

Most of the time you are not the one who writes any. The JSON.parse function returns any: it cannot know what the string holds. Hover over data in the editor, and the tooltip shows const data: any.

TypeScript
const data = JSON.parse('{"title": "report"}');
const label = data.title.toUpperCase();
const size: number = label;
console.log(size); // REPORT

Let's walk through the example line by line:

  1. data gets the type any from JSON.parse.
  2. data.title is any too, and so is the result of toUpperCase(). That makes the type of label any.
  3. size is declared as a number, yet tsc lets label go into it: an any value fits every type.
  4. The program prints REPORT, a string from a variable whose declaration says it holds a number.

any spreads through the program

The example shows the main danger of any: it infects its neighbors. A property read from an any value, and the result of calling its method, are any too. One value from JSON.parse quietly turned off the check for label, and through it fooled the variable size.

Here the customs picture stops working. In real life a stamp sits on one box, while in TypeScript it passes to everything taken out of that box.

Interviewers like to ask why any is dangerous. A good answer: any turns off the check for a value and for everything derived from it, so type mistakes turn into errors at run time.

Common mistake

A parameter was given any so that tsc would stop reporting an error in a call:

TypeScript
function double(x: any) { // ✗
    return x * 2;
}
console.log(double("ten"));

tsc stays silent, and the program prints NaN: the string "ten" cannot be multiplied by 2. With an honest type, x: number, the compiler would catch the call double("ten") before the program runs:

TEXT
error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

When tsc reports an error, fix the type or the call instead of turning the check off.

Key points

  • any turns the check off: tsc allows any method, property and assignment for such a value.
  • A mistake hidden by any does not disappear; it moves to run time.
  • JSON.parse returns any, and everything read from an any is any too.
  • An any value fits a variable of every type, so any fools even a number variable.