Using Promise.all like Promise.allSettled

I am looking to streamline the handling of Promise.allSettled in a more generic way.

Currently when using allSettled, it returns a list of both fulfilled and rejected results. I find this cumbersome and do not want to handle it everywhere in my code. My goal is to utilize allSettled similar to how Promise.all works - if there is an error, reject it, but wait until all promises have resolved or been rejected. This is crucial for my requirements.

private async allAndWait<T>(values: Iterable<PromiseLike<T>>): Promise<T[]> {
    const allSettled = await Promise.allSettled(values);
    const rejected = allSettled.find((promise) => promise.status === 'rejected') as PromiseRejectedResult | undefined;
    if (rejected) {
        throw rejected.reason;
    }
    return allSettled.map((promise) => (promise as PromiseFulfilledResult<T>).value);
}

I have created something similar to this logic, however, it does not allow me to send an array of different types of promises. Additionally, the return type only reflects the first type, whereas I desire an experience exactly like that of Promise.all.

https://i.sstatic.net/VDab2.png

Answer №1

Summary:

Modified async function allAndWait<T extends readonly unknown[] | []>(values: T & Iterable<PromiseLike<unknown>>): Promise<{-readonly [key in keyof T]: Awaited<T[key]>}>
async function allAndWait<T extends PromiseLike<unknown>>(values: Iterable<T>): Promise<Awaited<T>[]>
async function allAndWait<T extends readonly unknown[] | []>(values: Iterable<PromiseLike<unknown>>): Promise<any> {
  const allSettled = await Promise.allSettled(values) as PromiseSettledResult<Awaited<T[number]>>[]
  const rejected = allSettled.find((promise) => promise.status === 'rejected') as PromiseRejectedResult | undefined;
  if (rejected) {
      throw rejected.reason;
  }
  return allSettled.map((promise) => (promise as PromiseFulfilledResult<Awaited<T[number]>>).value)
}

My Process Explanation:

In the given code, the type inference for T is not correct. Ideally, T should be a union of all types in the input tuple (e.g., string | number). We can achieve this by redefining the type within the generic declaration (moving PromiseLike<unknown> would suffice).

async function allAndWait<T extends Iterable<PromiseLike<unknown>>>(values: T) ...

However, converting T from a union to a tuple poses a challenge. To maintain order in return types and extract specific types, a mapped type can be utilized:

{[key in keyof T]: Awaited<T[key]>}

Initially, utilizing a rest operator seemed feasible:

async function allAndWait<T extends Promise<unknown>[]>(...values: T): Promise<{[key in keyof T]: Awaited<T[key]>}> {...}

allAndWait(Promise.resolve("qwe"), Promise.resolve(2)) // typeof Promise<[string, number]>

Yet, due to inability to use the rest operator with iterables and their lack of tuples-like behavior, an alternative approach was necessary. A workaround involved using an intersection type:

async function allAndWait<T extends readonly unknown[] | []>(values: T & Iterable<Promise<unknown>>): Promise<{-readonly [key in keyof T]: Awaited<T[key]>}> {...}

An additional overload was provided for less powerful implementations with iterable inputs:

async function allAndWait<T extends PromiseLike<unknown>>(values: Iterable<T>): Promise<Awaited<T>[]>

This less powerful overload should be placed below the primary one to ensure it does not overshadow the more specific implementation.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Dexie is alerting us to a problem with a call that occurs before initialization

When setting up my application, I encountered an error related to the Courses Entity Class being called before initialization in my Dexie Database. Despite checking my code, I couldn't find any issues and there was no documentation available for this ...

Is there a way to navigate directly to the code in a TypeScript type definitions index.d.ts file within Visual Studio Code?

When I command-click on the express() function, it takes me to its definition: const app = express(); In vscode, it leads me to this line in an index.d.ts file: declare function e(): core.Express; However, when I try to jump to the definition of e(), i ...

Ways to assign values to an array within an object

I'm attempting to transfer the contents of one array into an array within an object, but I keep encountering this error: Type 'any[]' is not assignable to type '[]'. Target allows only 0 element(s) but source may have more. Here ...

Arrange a JavaScript map based on its values and ensure that a specific field index remains at the top position

I'm sure this question may seem simple to some, but as a JavaScript novice, I couldn't find the answer myself. Here is the code snippet I'm working with: Let map = new Map<String,String> map.set('0', select) map.set('1&a ...

Secure your TypeScript code by encapsulating it with protection mechanisms and distribute

Currently in the process of constructing an internal TypeScript "library" using webpack 1.14. I've set up an npm package and have it published on a private feed, which is working smoothly (able to utilize classes and interfaces from the library in o ...

Is there a way to identify which elements are currently within the visible viewport?

I have come across solutions on how to determine if a specific element is within the viewport, but I am interested in knowing which elements are currently visible in the viewport among all elements. One approach would be to iterate through all DOM elements ...

How to identify alterations in user input within Angular?

I need assistance with my search input functionality. I want to ensure that the this.searchProperties.emit is only triggered when the user interacts with the input field by touching it or making an input. The current issue is that the emit function gets ca ...

Inefficiency in POST method prevents data transmission to MongoDB

I've developed a MERN application and now I'm testing the backend using the REST client vscode extension. This is how it looks: `POST http://localhost:4000/signup Content-Type: application/json { "email": "<a href="/cdn-cgi ...

Tips for maintaining type information when using generics in constructors

class Registry<Inst, Ctor extends new (...args: unknown[]) => Inst, T extends Readonly<Record<string, Ctor>>> { constructor(public records: T) { } getCtor<K extends keyof T>(key: K) { return this.records[key] } getIns ...

Creating custom components in AngularJS 2 allows you to define methods unique to each component. Want to learn

I created my component (A) by combining multiple html elements, but I have two questions. How do I define methods (such as get, etc.) on my component? I have tried @Output, @ViewChild, etc. but they are not working. I am looking for an alternative way ...

Introducing cutting-edge intellisense for Typescript Vue in VSCode, featuring automatic import functionality specifically designed for the

Currently, I am working on a small project using Typescript and Vue in VSCode. In my setup, I have TSLint, TSLint Vue, Vetur, and Prettier plugins installed. Unfortunately, I am facing an issue with the intellisense "auto import" feature. It does not seem ...

Using TypeScript to define callback functions within the Cordova.exec method

I'm encountering an issue with the TypeScript definition for Cordova. The codrova.d.ts file doesn't allow for any function arguments in the success-callback and error-callback. To better illustrate my problem, here's a small example: Here ...

Showing Angular dropdown menu using Java HashMap

I am trying to fetch and display data from a HashMap in my Angular application by making a GET request to a Spring Application. Here is the code I have tried: Spring code: @GetMapping("gateways") public ResponseEntity<?> getGateways() { Map< ...

In Next.js, the switch button remains in the same state even after the page is refreshed

Is there a solution for this issue? I am currently developing a switch button for a configuration page. The problem arises when I toggle the switch from active to maintenance mode, save it successfully, but upon refreshing the page, the switch reverts back ...

Include a .done() callback within a customized function

In the small class, I have included these functions: var Ajax = { // Send new entry data to database endNewEntry: function (json) { $.post("/controllers/insertEntry.ajax.php", {"json": json}); }, loadView: function (view, target, extra) { ...

Exploring Objects using Typescript

I need help creating a mapper for objects that allows TypeScript to recognize the returned type correctly. For example: type ExampleObject = { text: string; // this object may have properties of any type number: number; }; const object: ExampleObjec ...

Utilizing a Firebase function with Angular

I created the following function: retrieveLikedProperties(): AngularFirestoreCollection<any> { return this.afs.collection('users', ref => ref.where('uid', '==', this._auth.currentUserId) .where(&a ...

The type of the element is implicitly set to 'any' because the expression 'keyof IMyObj' cannot be used to index the type

Trying to avoid specifying types in TypeScript and setting a value by accessing its key is causing a TypeScript error. Despite looking at multiple StackOverflow posts, I couldn't find a solution. I encountered a similar issue with my code and tried r ...

When I define a type in TypeScript, it displays "any" instead

Imagine a scenario where we have a basic abstract class that represents a piece in a board game such as chess or checkers. export abstract class Piece<Tags, Move, Position = Vector2> { public constructor(public position: Position, public tags = nul ...

Tips for resolving the issue: Uncaught (in promise) SyntaxError: Unexpected end of input in Fetch API

When I click the button, I am executing this function. Despite adding a header in my API, an error is still being displayed. Here is the code snippet for the function: let getData = () => { console.log("getData function started"); ...