Typescript promise error type

Saved searches

Use saved searches to filter your results more quickly

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.

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

Different types for rejected/fulfilled Promise #7588

Comments

I’m trying to understand how to correctly type a rejected promise. I expect the following code to compile.

const bar: Promisenumber> = Promise.resolve(1) .then(() => Promise.rejectstring>(new Error('foo')))
main.ts(7,7): error TS2322: Type 'Promise' is not assignable to type 'Promise'. Type 'string' is not assignable to type 'number'. 

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:

Thanks for the reply. For context I am using the built in type definitions for Promise , now provided in TypeScript itself.

In your example, since bar has type Promise, then the final promise in the chain (which is the promise assigned to bar) has to match that type.

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:

const bar: Promise = Promise.resolve(1) .then(() => Promise.reject(new Error('foo'))) 
const bar: Promise = Promise.resolve(1) .then(() => < throw new Error('foo') >) 
Type 'Promise' is not assignable to type 'Promise'. Type 'void' is not assignable to type 'number'. 

I can workaround it with the type assertion as you suggested, but it’s not ideal.

The Promise type comes from the type definition for Promise.reject :

reject(reason: any): Promisevoid>; rejectT>(reason: any): PromiseT>;

Your original example is using the first overload. Since there is no information available to infer the fulfillment type, it uses void . The second overload allows you to explicitly state the promise type.

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 Promise.reject type definition was changed to:

reject(reason: any): Promiseany>;

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 void was chosen over any for some reason overlooked here.

Источник

Saved searches

Use saved searches to filter your results more quickly

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.

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

Promise rejection type. #39680

Promise rejection type. #39680

Awaiting More Feedback This means we’d like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

Search Terms

Suggestion

Add ability to type Promise rejections.

// Current Promise Constructor Implementation: new T>(executor: (resolve: (value?: T | PromiseLikeT>) => void, reject: (reason?: any) => void) => void): PromiseT>; // Proposed Change: new T, E = any>(executor: (resolve: (value?: T | PromiseLikeT>) => void, reject: (reason?: E) => void) => void): PromiseT, E>;

Use Cases

When handling promise rejections, the type any isn’t very useful. I would be useful to have the rejection have an actual type without the need to cast or type guard.

Examples

Promise.rejectnever, string>('hello world') .catch(reason =>  console.error(reason.length); // `reason` is of type string. >);
class MyError extends Error  // . > Promise.rejectnever, MyError>(new MyError(/* . */)) .catch(reason =>  // `reason` is of type MyError. const info = reason.getMoreInfo(); // . >);

Checklist

My suggestion meets these guidelines:

  • This wouldn’t be a breaking change in existing TypeScript/JavaScript code
  • This wouldn’t change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn’t a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript’s Design Goals.

The text was updated successfully, but these errors were encountered:

RyanCavanaugh added Awaiting More Feedback This means we’d like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript labels Jul 21, 2020

I don’t feel like they rejection type always has to be of type any / unknown .

It is obviously possible to detect what the rejection type is when Promise.reject is used. The hard bit would be detecting rejections caused by a throw statement inside an async function. But if we approach it from the perspective of a throw statement just being an alternative type of return statement, it seems possible to me (but maybe quite difficult).

I’ve been having a bit of a play with this to see what it would be like add support. This is what I’ve got so far just by playing with type definitions.

p2 // p2 is of type Promise .then((v2) => void cosnole.log(v2)) // v2 is of type number .catch((e2) => void console.error(e2)); // e2 is actually type string | ReferenceError, not string

Why would the type be string | ReferenceError ? Isn’t TypeScript already be reporting ReferenceError when they happen (2304)? (Or is that a strict mode only thing? If so then this proposal could just be for strict mode.)

Yes, TS will report 2304 in this obvious case however emitted JS code will still have a change to receive both string and ReferenceError . Idea is to show that if there is something between resolve and catch — there are no guarantees that code between them wont throw something else (e.g. failed network request, incorrect normalize function etc.)

Looks like string will be only true for case p2.catch(. ) but only if you believe that there are no other errors before resolve / reject (which might not be always true).

Could you give a small example?

If myPromise.then(. ).catch(. ) can’t be handled due to this but myPromise.catch(. ) could be, imo that’s still worth pursuing.

In unsound cases or unknown external code (e.g. computedBoolean ) there is always a chance to have behavior that will throw

declare const computedBoolean: (params: any) => boolean; // but in general case might throw const list = [id: 111>, id: 222>]; function firstThreeIds(data: Arrayid: number>>): number[]  return [ data[0].id, data[1].id, data[2].id // no compile time error, but will throw ]; > const p = new Promisenumber[], string>((resolve, reject) =>  if (computedBoolean(list))  // can throw before resolve resolve(firstThreeIds(list)); // wil throw before resolve > else  reject("foo"); > >); p .catch((e) =>  /* . */>); // actually string | TypeError

So it looks like closest thing e can be typed is E | Error in definition ( string | Error in current example).
And again if computedBoolean won’t throw anything else (not sure which case will be encountered more often).

Источник

TypeScript: Narrow types in catch clauses

Stefan Baumgartner

When you are coming from languages like Java, C++, or C#, you are used to doing your error handling by throwing exceptions. And subsequently, catching them in a cascade of catch clauses. There are arguably better ways to do error handling, but this one has been around for ages and given history and influences, has also found its way into JavaScript.

So, this is a valid way of doing error handling in JavaScript and TypeScript. But try to follow the same flow as with other programming languages, and annotate the error in your catch clause.

try  
// something with Axios, for example
> catch(e: AxiosError)
// ^^^^^^^^^^ Error 1196 💥
>

TypeScript will error with TS1196: Catch clause variable type annotation must be ‘any’ or ‘unknown’ if specified.

There are a couple of reasons for this:

1. Any type can be thrown #

In JavaScript, you are allowed to throw every expression. Of course, you can throw “exceptions” (or errors, as we call them in JavaScript), but it’s also possible to throw any other value:

throw "What a weird error"; // 👍
throw 404; // 👍
throw new Error("What a weird error"); // 👍

Since any valid value can be thrown, the possible values to catch are already broader than your usual sub-type of Error .

2. There is only one catch clause in JavaScript #

JavaScript only has one catch clause per try statement. There have been proposals for multiple catch clauses and even conditional expressions in the distant past, but they never manifested. See JavaScript — the definitive guide for – hold it! – JavaScript 1.5 – what.

Instead, you should use this one catch clause and do instanceof and typeof checks (Source):

try  
myroutine(); // There's a couple of errors thrown here
> catch (e)
if (e instanceof TypeError)
// A TypeError
> else if (e instanceof RangeError)
// Handle the RangeError
> else if (e instanceof EvalError)
// you guessed it: EvalError
> else if (typeof e === "string")
// The error is a string
> else if (axios.isAxiosError(e))
// axios does an error check for us!
> else
// everything else
logMyErrors(e);
>
>

Note: The example above is also the only correct way to narrow down types for catch clauses in TypeScript.

And since all possible values can be thrown, and we only have one catch clause per try statement to handle them, the type range of e is exceptionally broad.

3. Any exception can happen #

But hey, since you know about every error that can happen, wouldn’t be a proper union type with all possible “throwables” work just as well? In theory, yes. In practice, there is no way to tell which types the exception will have.

Next to all your user-defined exceptions and errors, the system might throw errors when something is wrong with the memory when it encountered a type mismatch or one of your functions has been undefined. A simple function call could exceed your call stack and cause the infamous stack overflow.

The broad set of possible values, the single catch clause, and the uncertainty of errors that happen only allow two possible types for e : any and unknown .

What about Promise rejections? #

The same is true if you reject a Promise. The only thing TypeScript allows you to specify is the type of a fulfilled Promise. A rejection can happen on your behalf, or through a system error:

const somePromise = () => new Promise((fulfil, reject) =>  
if (someConditionIsValid())
fulfil(42);
> else
reject("Oh no!");
>
>);

somePromise()
.then(val => console.log(val)) // val is number
.catch(e =>
console.log(e) // e can be anything, really.
>)

It becomes clearer if you call the same promise in an asnyc / await flow:

try  
const z = await somePromise(); // z is number
> catch(e)
// same thing, e can be anything!
>

Bottom line #

Error handling in JavaScript and TypeScript can be a “false friend” if you come from other programming languages with similar features. Be aware of the differences, and trust the TypeScript team and type checker to give you the correct control flow to make sure your errors are handled well enough.

Cover of Front-End Tooling

I’ve written a book on TypeScript! Check out TypeScript in 50 Lessons, published by Smashing Magazine

Источник

Читайте также:  How to import own modules in python
Оцените статью