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 Promise
s and Observable
s.
TypeScript 2.4 introduces tightens this up when relating two callback types. For example:
interface Mappable<T> {
map<U>(f: (x: T) => U): Mappable<U>;
}
declare let a: Mappable<number>;
declare let b: Mappable<string | number>;
a = b;
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.