Improved any Inference

Previously, if TypeScript couldn’t figure out the type of a variable, it would choose the any type.

  1. let x; // implicitly 'any'
  2. let y = []; // implicitly 'any[]'
  3. let z: any; // explicitly 'any'.

With TypeScript 2.1, instead of just choosing any, TypeScript will infer types based on what you end up assigning later on.

This is only enabled if —noImplicitAny is set.

Example
  1. let x;
  2. // You can still assign anything you want to 'x'.
  3. x = () => 42;
  4. // After that last assignment, TypeScript 2.1 knows that 'x' has type '() => number'.
  5. let y = x();
  6. // Thanks to that, it will now tell you that you can't add a number to a function!
  7. console.log(x + y);
  8. // ~~~~~
  9. // Error! Operator '+' cannot be applied to types '() => number' and 'number'.
  10. // TypeScript still allows you to assign anything you want to 'x'.
  11. x = "Hello world!";
  12. // But now it also knows that 'x' is a 'string'!
  13. x.toLowerCase();

The same sort of tracking is now also done for empty arrays.

A variable declared with no type annotation and an initial value of [] is considered an implicit any[] variable.However, each subsequent x.push(value), x.unshift(value) or x[n] = value operation evolves the type of the variable in accordance with what elements are added to it.

  1. function f1() {
  2. let x = [];
  3. x.push(5);
  4. x[1] = "hello";
  5. x.unshift(true);
  6. return x; // (string | number | boolean)[]
  7. }
  8. function f2() {
  9. let x = null;
  10. if (cond()) {
  11. x = [];
  12. while (cond()) {
  13. x.push("hello");
  14. }
  15. }
  16. return x; // string[] | null
  17. }