Covariant checking in callback parameters

TypeScript 2.4 changed the way the type system behaves internally to improve the error detection in nested callbacks and promises:

TypeScript's checking of callback parameters is now covariant concerning immediate signature checks. Previously it was bivariant, which could sometimes let incorrect types through. Basically, this means that callback parameters and classes that contain callbacks are checked more carefully, so TypeScript will require stricter types in this release. This is particularly true of Promises and Observables due to the way in which their APIs are specified.

In TypeScript versions before 2.4, the following example was considered valid, and no errors were thrown:

declare function someFunc( 
    callback: ( 
    nestedCallback: (error: number, result: any) => void 
    ) => void 
): void; 
 
someFunc( 
    ( 
        nestedCallback: (e: number) => void // Error 
    ) => { 
        nestedCallback(1); 
    } 
); 

In TypeScript versions following the 2.4 release, we need to add the complete signature of nestedCallback to solve this error:

someFunc( 
    ( 
        nestedCallback: (e: number, result: any) => void // OK 
    ) => { 
        nestedCallback(1, 1); 
    } 
); 

Thanks to the internal change in the TypeScript type system, the following error is also detected:

let p: Promise<number> = new Promise((res, rej) => { 
    res("error"); // Error 
}); 

Before TypeScript 2.4, the preceding promise would have been inferred as Promise<{}> because we forgot to add the generic <number> argument when we created an instance of the Promise class. The error string would then have been considered a valid instance of {}.

This is a clear example of why it is recommended that you upgrade TypeScript regularly. Each new version of TypeScript introduces new features that are able to detect new errors for us.