Hamed Mahdizadeh
Hamed Mahdizadeh

Reputation: 976

typescript get values of Promise.allSettled

I want to get values of Promise allSettled result in typescript code. In JavaScript this work well.

  Promise.allSettled([
      Promise.resolve(33),
      new Promise(resolve => setTimeout(() => resolve(1000), 0)),
      25000,
      Promise.reject(new Error('failed!'))
    ])
    .then(values => {
      let allValues = values.filter(c=>c.status === 'fulfilled').map(v=>v.value);
      console.log(allValues);
    });

But in typescript I can't find correct syntax. the item just have status and has no value property. I am using the latest version of typescript 3.9.7

Upvotes: 4

Views: 6997

Answers (3)

Ivan Burnaev
Ivan Burnaev

Reputation: 2730

Oh my, 3 y.o. question. Anyway, better late than never. =)
I would suggest to use a few helper type guards to actually filter fulfilled and rejected results.

const isFullfilled = <T>(
  value: PromiseSettledResult<T>
): value is PromiseFulfilledResult<T> => {
  return value.status === 'fulfilled'
}

const isRejected = <T>(
  value: PromiseSettledResult<T>
): value is PromiseRejectedResult => {
  return value.status === 'rejected'
}

const fetchNumbers = () => {
  return Promise.allSettled([
    Promise.resolve(33),
    new Promise<number>((resolve) => setTimeout(() => resolve(1000), 0)),
    25000,
    Promise.reject(new Error('failed!')),
  ])
}

    
const main = async () => {
  const responses = await fetchNumbers()
  const doubledNumbers = responses
    .filter(isFullfilled)
    .map((response) => response.value * 2)
}

main()

As you can see there are 2 type guards which forces the filter method to actually return a correct type either PromiseFulfilledResult or PromiseRejectedResult.

You can get more information about how the guards work right here: https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types

Upvotes: 1

Hamed Mahdizadeh
Hamed Mahdizadeh

Reputation: 976

Ok I finally found the correct syntax for using Promise.allSettled in typescript:

Update: Thanks to @myol I updated the code without unnecessary map:

const dummyResolve1 =  Promise.resolve(1000);
const dummyResolve2 = new Promise(resolve => setTimeout(() => resolve(2000), 0));
const dummyError = Promise.reject(new Error('failed'));
const dummyPromises = [dummyResolve1, dummyResolve1, dummyError];

Promise.allSettled(dummyPromises)
  .then(results => {
    const allValues = (results.filter(c=>c.status === 'fulfilled') as PromiseFulfilledResult<any>[])
    .map(c=>c.value);

    console.log(allValues);

    const failedResults = 
    (results.filter(c=>c.status === 'rejected') as PromiseRejectedResult[])
    .map(c=>c.reason);
    
    console.log(failedResults);
});

Old code:

Promise.allSettled([
  Promise.resolve(1000),
  new Promise(resolve => setTimeout(() => resolve(2000), 0)),
  1500,
  Promise.reject(new Error('failed'))
])
.then(values => {
  let allValues = values.filter(c=>c.status === 'fulfilled').map(c=> <PromiseFulfilledResult<any>>c).map(c=>c.value);
  console.log(allValues);
  let failedResults =  values.filter(c=>c.status === 'rejected').map(c=> <PromiseRejectedResult>c).map(c=>c.reason);
  console.log(failedResults);
});

Upvotes: 10

myol
myol

Reputation: 9828

I think you really want the following;

const fulfilledValues: any[] = (values as PromiseFulfilledResult<any>[])
  .filter(res => res.status === 'fulfilled')
  .map(res => res.value);
console.log(fulfilledValues);

const rejectedReasons: any[] = (values as PromiseRejectedResult[])
  .filter(res => res.status === 'rejected')
  .map(res => res.reason);
console.log(rejectedReasons);

No need for an extraneous JS .map call just to use type assertion in TS.

Upvotes: 1

Related Questions