Improved inference for generics
TypeScript 2.4 introduces a few wonderful changes around the way generics are inferred.
Return types as inference targets
For one, TypeScript can now make inferences for the return type of a call.This can improve your experience and catch errors.Something that now works:
function arrayMap<T, U>(f: (x: T) => U): (a: T[]) => U[] {
return a => a.map(f);
}
const lengths: (a: string[]) => number[] = arrayMap(s => s.length);
As an example of new errors you might spot as a result:
let x: Promise<string> = new Promise(resolve => {
resolve(10);
// ~~ Error!
});
Type parameter inference from contextual types
Prior to TypeScript 2.4, in the following example
let f: <T>(x: T) => T = y => y;
y
would have the type any
.This meant the program would type-check, but you could technically do anything with y
, such as the following:
let f: <T>(x: T) => T = y => y() + y.foo.bar;
That last example isn’t actually type-safe.
In TypeScript 2.4, the function on the right side implicitly gains type parameters, and y
is inferred to have the type of that type-parameter.
If you use y
in a way that the type parameter’s constraint doesn’t support, you’ll correctly get an error.In this case, the constraint of T
was (implicitly) {}
, so the last example will appropriately fail.
Stricter checking for generic functions
TypeScript now tries to unify type parameters when comparing two single-signature types.As a result, you’ll get stricter checks when relating two generic signatures, and may catch some bugs.
type A = <T, U>(x: T, y: U) => [T, U];
type B = <S>(x: S, y: S) => [S, S];
function f(a: A, b: B) {
a = b; // Error
b = a; // Ok
}