-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Different types for rejected/fulfilled Promise #7588
Comments
The declare class Promise<T> implements Thenable<T> {
...
then<U>(onFulfilled?: (value: T) => U | Thenable<U>, onRejected?: (error: any) => U | Thenable<U>): Promise<U>;
... So both In your example, since |
Thanks for the reply. For context I am using the built in type definitions for
I expected the final promise in the chain wouldn't have to match this type if it was a rejected promise. If you take the type assertion out, it will fail:
Also if you throw:
I can workaround it with the type assertion as you suggested, but it's not ideal. |
The reject(reason: any): Promise<void>;
reject<T>(reason: any): Promise<T>; Your original example is using the first overload. Since there is no information available to infer the fulfillment type, it uses Perhaps what you are wanting is for TypeScript to be able to work out that the last promise in the chain is always rejected and therefore the fulfilment value is irrelevant? It could effectively do this if the reject(reason: any): Promise<any>; Which basically says " This will never be fulfiled so it's effectively compatible with any fulfilment value type since such a value will never be produced." That might be a specific suggestion worth making to the team. I'm not sure if |
I just came across this. How should I learn the correct typings for such APIs? Just read the declaration files, or is there are more reader-friendly format published somewhere? |
@mhegazy why was this issue closed? I was expecting to find a generic type with two type arguments, e.g. My use-case is a simple wrapper around an |
- run "npm update" - clean package.json - switch deprecated packages to non-deprecated ones - mainly switch from "tsd" to "typings" NOTE: node.d.ts and require.d.ts have been manually edited to prevent Require and NodeRequire from clashing (see e.g. DefinitelyTyped/DefinitelyTyped#7049 (comment)) - replace "throw err; return null;" with "return Promise.reject(err)", as typescript and throwing does not work together (see e.g. microsoft/TypeScript#7588) - fix some other typing stuff - fix 'use strict';s to be on top of the files Please run "rm -r node_modules; npm install" after getting this commit.
- run "npm update" - clean package.json - switch deprecated packages to non-deprecated ones - mainly switch from "tsd" to "typings" NOTE: node.d.ts and require.d.ts have been manually edited to prevent Require and NodeRequire from clashing (see e.g. DefinitelyTyped/DefinitelyTyped#7049 (comment)) - replace "throw err; return null;" with "return Promise.reject(err)", as typescript and throwing does not work together (see e.g. microsoft/TypeScript#7588) - fix some other typing stuff - fix 'use strict';s to be on top of the files Please run "rm -r node_modules; npm install" after getting this commit.
I agree with @mindplay-dk that // if
fn1: (a: A) => Promise<B, Error1>
fn2: (b: B) => Promise<C, Error2>
// then
fn1(a).then(fn2): Promise<C, Error1 | Error2> And a promise that never rejects could have the type |
Can you guarantee that a promise adheres to that signature? What if there's an unexpected exception inside your promise handler? |
You can chain the promises, where the error type cannot be inferred while the resolution type can be: function foo(result: any): number {
if (typeof result !== 'bar') throw new TypeError('Not bar');
return 1;
}
const result = 'foo';
const p = new Promise<string, Error>((resolve, reject) => {
if (result === 'foo') {
resolve(result);
}
else {
reject(new Error('I wanted foo'));
}
)
.then(foo) // return type of `foo` changes this to Promise<number, Error>
.catch((err) => {
err; // runtime `TypeError` design time `Error` :-(
}); |
Doesn't the same apply to any function? |
Yes exactly, but you haven't asserted what types of errors that a function might throw, unlike a |
It's unfortunate, and I wish this was possible. If promises didn't trap exceptions things would be different, but unless typescript gets typed exceptions I can't see how it would work. |
@kitsonk @heyimalex I'm not sure I understand. It seems to me that adding a second param is strictly better than having a second param that is an |
The only times that exceptions are typed is in catch blocks and rejected promise handlers, so it's not really a general problem. Even if you know the type of a rejected promise is Admittedly that's a pretty academic argument, and having typed rejections would be awesome in terms of self documenting promise-based apis. |
That makes sense, thanks for the explanation. So in TS Personally, I like the idea of a more functional way to capture error types, something like a Scala
I agree. |
With default type arguments in the 2.3 Release, couldn't it be argued that the reject type can be defaulted to its current |
Can this be reopened? I think that disallowing the user to specify the error value is very counterproductive, and with the new release, there should be no breaking changes. The whole point of TypeScript is to allow static typing, and this is forcing 50% of the promise's type information to be implicit/dynamic. Considering how widespread Promises are, I think this is worth considering. |
@craftytrickster The value passed to the reject handler is dynamic. This issue was that it's not possible to do this safely, not that two type arguments are too verbose. |
@heyimalex I do understand that the errors are very dynamic and hard to predict. I still think that defaulting to void and giving the user at least the chance to structure their errors is still valuable (as hard/tedious as it may be to catch + rethrow a specific type). But if I am in the minority here I understand your concerns. |
@heyimalex I still really think that there could be some value in having this. Doing |
for those stumbling across this, #6283 IMHO gives a better concise answer |
TypeScript 1.8.9
I'm trying to understand how to correctly type a rejected promise. I expect the following code to compile.
Error:
Is it possible to have different types for a Promise when it is rejected and fulfilled?
The text was updated successfully, but these errors were encountered: