TypeScript Version: 1.8.10
Code
declare function a<T>(f: (x: T) => T): T; // callback takes and returns the same generic type
declare function b<T>(f: (x: number) => T): T; // callback returns generic type, but doesn't take it
interface X { x: number; }
a<X>(x => ({ x: 1 })); // ok, inferring isn't needed
a((x: X) => ({ x: 1 })); // ok, inferred by argument type
a(x => ({ x: 1 })); // infers T as {}
// on the other hand
b(x => ({ x: 1 })); // infers T as X
Expected behavior:
In a(x => ({ x: 1 })), T is inferred as { x: number }
Actual behavior:
In a(x => ({ x: 1 })), T is inferred as { }
I believe the problem here is we have two inference sites for T -- the return type of the function ({ x: number }), and the type of the parameter (which ends up being { } for lack of better inference), and the most general type among them is then { }.
There might be some fix here without other side effects but I don't know what it would be.
So should we create a proposal to fix that?
It would be very helpful!
@RyanCavanaugh
Just imagine how convenient it was to write this (for example - Promise executor):
const promise = new Promise((resolve, reject) => {
resolve(123);
});
promise.then((res) => {
console.log('I get called:', res.toFixed());
});
Also disappear errors like this:
const promise = new Promise((resolve, reject) => {
resolve(123);
resolve("!");
resolve(true);
});
But now we have...
const promise = new Promise<number>((resolve, reject) => {
resolve(123);
});
//or
const promise: Promise<number> = new Promise((resolve, reject) => {
resolve(123);
});
// more example
function doSome(): Promise<number> { // let's say that do Some logic is very complicated and we want to explicitly specify the results
return new Promise<number>((resolve, reject) => { // <number> for greater security logic inside Promise executor
resolve(123);
});
}
Many similar problems will go into oblivion if this is done
...and more
@tsofist I cannot agree regarding #10717, it is not the case for sure
@Igorbek my bad
See this.
type AABB = 'AA' | 'BB';
let arr: any[];
let arr2: AABB[] = arr.map(v => 'AA');
let arr3: AABB[] = arr.map(v => 'BB');
If I want it work, I could only use this:
let arr2: AABB[] = arr.map(v => 'AA' as 'AA');
'AA' as 'AA' is really unnecessary...
Most helpful comment
@RyanCavanaugh
Just imagine how convenient it was to write this (for example - Promise executor):
Also disappear errors like this:
But now we have...
Many similar problems will go into oblivion if this is done
11701
11537
3038
10785
10609
11058
9660
11537
11877
...and more