Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type error on response of Promise.allSettled()

I've been trying to use Promise.allSettled on NodeJS with Typescript recently, and I'm facing issues with the response. the allSettled method returns an array with status: "rejected" | "fulfilled" and a value, in case it's fulfilled. The problem is, when I try to access the value of the response, I get the following errors:

Property 'value' does not exist on type 'PromiseSettledResult<unknown>'.
Property 'value' does not exist on type 'PromiseRejectedResult'.ts(2339)

Below I'll leave a simple example so you can copy the code and try yourself:

const p1 = Promise.resolve(50); 
const p2 = Promise.resolve(100); 

const promiseArray = [p1, p2]; 
  
Promise.allSettled( promiseArray ). 
  then( results => results.forEach( result =>  
    console.log(result.status, result.value)));

If I run this code on my project, I get an error because of result.value at the end.

I'm running my node on version 12.18.3 on Windows, and I've set my target on the tsconfig.json as ES2020 to be able to use the method itself.

like image 877
Cassio Groh Avatar asked Sep 07 '20 20:09

Cassio Groh


3 Answers

Got same error in case of filter promises array:

const promises = ids.map((id) => <some BE API call>);
const resolvedPromises = await Promise.allSettled(promises);
resolvedPromises.filter(({ status }) => status === 'fulfilled').map((p) => p.value);

Error screenshot

The problem is allSettled returns PromiseSettledResult, which is not exported at all (I use lib.es2020.promise in tsconfig):

interface PromiseFulfilledResult<T> {
    status: "fulfilled";
    value: T;
}

interface PromiseRejectedResult {
    status: "rejected";
    reason: any;
}

type PromiseSettledResult<T> = PromiseFulfilledResult<T> | PromiseRejectedResult;

and .map doesn't understand that all rejected promises were filtered in filtered method.

So, I even can't import types and cast values to them.

As a temporary solution I suppressed ESLint and TSC rules with comments:

  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  // @ts-ignore

Then I created same to PromiseFulfilledResult interface in the project and used types casting:

resolvedPromises.filter(({ status }) => status === 'fulfilled').map((p) => (p as PromiseFulfilledResult).value);

As a result I got rid of on error and ESLint/TS rules ignoring comments.

like image 64
Artyom Ganev Avatar answered Oct 22 '22 16:10

Artyom Ganev


@jonrsharpe answered it: You only have a value attribute where the status is fulfilled, and you're not checking for that.

So using my own example, it can be fixed as the following:

const p1 = Promise.resolve(50); 
const p2 = Promise.resolve(100); 

const promiseArray = [p1, p2]; 
  
Promise.allSettled( promiseArray ). 
  then( results => results.forEach( result =>  
    console.log(result.status,
                result.status === 'fulfilled' && result.value
    );
  ));

It now verifies if the promise was fulfilled and then prints the value, if it's the case.

like image 20
Cassio Groh Avatar answered Oct 22 '22 16:10

Cassio Groh


You can avoid this error if you make a type statement after calling the allSettled method. For example, you can immediately enter a type for typescript as follows:

const promises = await Promise.allSettled([
  fetch(url).then((response) => response.json()),
  fetch(url).then((response) => response.json()),
]) as {status: 'fulfilled' | 'rejected', value: SomeType}[];

After that it will work correctly:

const resolvedPromises = promises.filter(({ status }) => status === 'fulfilled');
const responses = resolvedPromises.map((promise) => promise.value);
like image 43
Denis Lopatin Avatar answered Oct 22 '22 17:10

Denis Lopatin