Search code examples
typescripttypescastinganyexplicit

Why can 'any' be assigned to any type without explicitly casting it first?


Why is the following code snippet not raising any errors or warnings?

{
    let x: number;
    let y: any;

    y = "hello";
    x = y;
}

My expectations are: anything should be assigned to y as it is explicitly typed as any, but only numbers should be assigned to x as it is explicitly typed as number and if an any needs to be assigned to x then that should be explicitly cast to number:

x = y as number; 

How could the current behaviour considered to be acceptable or as a good idea and not a bug in the first place? Moreover, is there a way to force the compiler to raise an issue about this and only accept explicit casting?


Extra Info:

  • tsc version: 3.2.2
  • compiler options:
{
    "target": "ES5",
    "noImplicitAny": true,
    "strictNullChecks": true,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "strictBindCallApply": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true
}

Solution

  • This is the defined behavior of any. This type is at the same type :

    • Assignable from any other type
    • Assignable to any other type (the issue you highlight)
    • Any operation is allowed with it (indexing, calling, property access, operator application, all are allowed and not checked in any way)

    There several uses for any. A couple of examples:

    • Allow easy transition from js to ts. While you are converting the code to typescript any can be very useful to allow you to compile the code successfully while you are still converting.
    • Allow easy interop with existing JS code (just type something as any and you can use it as you would in JS). Although you are probably better off writing definitions in the long run.

    All this being said, I would avoid any at all cost in Typescript today. Typescript 3.0 introduces the unknown type which behaves like you expect any to behave (ie, you can assign anything to it but it is not assignable to any other type). Read more about unknown here

    A few options to rid yourself of any:

    • noImplictAny compiler setting prevents the compiler from inferring any if you don't specify a type (it will issue an error instead)
    • no-unsafe-any tslint rule, prevents uses of any in a dynamic way, ie uses are only allowed if they would work for {} | null | undefined
    • no-any tslint rule, prevents any and all uses of any