Strict contravariance for callback parameters

TypeScript has always compared parameters in a bivariant way.There are a number of reasons for this, but by-and-large this was not been a huge issue for our users until we saw some of the adverse effects it had with Promises and Observables.

TypeScript 2.4 introduces tightens this up when relating two callback types. For example:

  1. interface Mappable<T> {
  2. map<U>(f: (x: T) => U): Mappable<U>;
  3. }
  4. declare let a: Mappable<number>;
  5. declare let b: Mappable<string | number>;
  6. a = b;
  7. b = a;

Prior to TypeScript 2.4, this example would succeed.When relating the types of map, TypeScript would bidirectionally relate their parameters (i.e. the type of f).When relating each f, TypeScript would also bidirectionally relate the type of those parameters.

When relating the type of map in TS 2.4, the language will check whether each parameter is a callback type, and if so, it will ensure that those parameters are checked in a contravariant manner with respect to the current relation.

In other words, TypeScript now catches the above bug, which may be a breaking change for some users, but will largely be helpful.