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:
const amount: number = 42;
console.log(amount.toUpperCase()); // ✗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:
const amount: any = 42;
console.log(amount.toUpperCase()); // ✗TypeError: amount.toUpperCase is not a functiontsc 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.
const data = JSON.parse('{"title": "report"}');
const label = data.title.toUpperCase();
const size: number = label;
console.log(size); // REPORTLet's walk through the example line by line:
datagets the typeanyfromJSON.parse.data.titleisanytoo, and so is the result oftoUpperCase(). That makes the type oflabelany.sizeis declared as anumber, yettscletslabelgo into it: ananyvalue fits every type.- 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:
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:
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
anyturns the check off:tscallows any method, property and assignment for such a value.- A mistake hidden by
anydoes not disappear; it moves to run time. JSON.parsereturnsany, and everything read from ananyisanytoo.- An
anyvalue fits a variable of every type, soanyfools even anumbervariable.