1

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
}
Peter Varo
  • 11,726
  • 7
  • 55
  • 77

1 Answers1

2

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
Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357
  • 2
    The technical description is that `any` is a the same time a *top type* (a type that is a supertype of every other type) *and* a *bottom type* (a type is a subtype of every other type). As you can imagine, this is pretty "weird" and you have stumbled across this weirdness. Modern Typescript also has a "proper" top type (`unknown`) and bottom type (`never`). Actually, owing to compatibility with JavaScript, `undefined` and `null` are also bottom types by default, but you can enable more strict checking. – Jörg W Mittag Jan 08 '19 at 13:17