-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
2.1 breaks promise chaining #12886
Comments
The problem here is how function return type is inferred. An even reduced example. declare var rejected: Promise<never>
declare var resolved: Promise<void>
function Then(n: number) { // inferred as Promise<never>, so it is a subtype of `Promise<number>`
return n !== 200 ? rejected : resolved
}
var a: Promise<void> = Promise.resolve(4).then(Then); // error here because then resolves to Promise<number> Current workaround is annotate your function return type to The problem may be function signature with void and never as argument and return type. Curiously, if we can add a type tag, just like nominal-type brand, it can resolve the problem. Since type parameter interface Promise<T> {
'@@__typeTag': T
/// other signatures ...
} @rbuckton what's your opinion? |
This is odd - if I write the following: var x: Promise<void>
var y: Promise<never>
var a = Math.random() ? x : y; the type of |
@DanielRosenwasser var x: Promise<void>
var y: Promise<never>
x = y
y = x The code above compiles, Promise at type level is effectively a collection of function type. So I reduced the problem down to this. type NeverFunc = (f: (t: never) => never ) => NeverFunc
type VoidFunc = (f: (t: void) => void) => VoidFunc
var a: NeverFunc
var b: VoidFunc
a = b
b = a It compiles because of bivariance, which is the known old problem all the way back to #1394, #10717. I wonder whether the type tag approach mentioned above can mitigate this by guaranteeing covariant behavior. Yet I'm happier to see strict variance can come to TypeScript. |
I'm having a similar issue which I am not able to work-around with any of the above information. interface TypeA {
a: string;
}
interface TypeB {
b: string;
}
declare function fnA(): Promise<TypeA>;
declare function fnB(a: TypeA): Promise<TypeB>;
fnA()
.then((instanceOfA) => fnB(instanceOfA))
.then((instanceOfB) => {
console.log(instanceOfB.b);
}); The compiler complains on the console.log call because 'instanceOfB' is identified as being TypeA which does not have member 'b'. Additionally, VSCode also sees the issue (which makes sense). instanceB should get its type signature from the return signature of the value return in the previous then, but it is not. I even tried EXPLICITLY defining the return type of the function passed to .then, but it still complained: .then((instanceOfA): Promise<TypeB> => fnB()) This has made it impossible for us to update to 2.1 without doing nasty stuff like double casting: console.log((<TypeB><any>instanceOfB).b); |
@raijinsetsu I have the same problem. I have chains of promises that transforms the information down the line. This compiles fine with tsc 2.0.8, but breaks in 2.1 - in that the compiler insists the type is the same as on the root promise. I suspect it might be the library definitions, the d.ts file, that is outdated - but not sure how to progress. Sublime Text with Typescript also complains about this issue, even if I only have tsc 2.0.8 on my machine. This mix of versions makes the code challenging to work with. Any help on this would be greatly appreciated. Edit: Seems that this is under investigation in: 10977 |
This (apparently valid) code compiled OK with TypeScript 2.0:
With TypeScript 2.1.4 it gives:
tsconfig.json
:It seems that the problem comes when promises are chained. For instance when removing the
.then()
chain, compilation runs without any error:The text was updated successfully, but these errors were encountered: