Combine a collection of promises into a single promise that may contain either strings or numbers: [P<string>, P<number>] -> Promise<string | number>

I'm currently working on a function that aims to retrieve the first resolved value from an array of Promises

const findFirstResolvedValue = (...promises: Array<Promise<any>>): Promise<any> {
   // ...
}

const result = findFirstResolvedValue(
  new Promise<string>(),
  new Promise<number>(),
  new Promise<boolean>()
)

result // Promise<string | number | boolean>

Answer №1

If you want to utilize the functionality of Promise.race(), you can do so in the following manner:

const result = Promise.race([
  new Promise<string>(() => {}),
  new Promise<number>(() => {}),
  new Promise<boolean>(() => {})
]);

result // Promise<string | number | boolean>

It correctly infers the return type.

Answer №2

To effectively handle this situation, we can utilize TypeScript's Generic Rest Parameters.

By implementing this approach, we can define a generic tuple type that captures the specific type of each argument when the function is invoked.

Let's delve into the process:

Initially, we will capture the type of each argument passed to the function.

const firstSettledValue = <P extends Promise<any>[]>(...promises: P) => {}

const v = firstSettledValue(
  Promise.resolve('Hello World'),
  Promise.resolve(15),
  Promise.resolve(false)
)

Subsequently, we can derive a union type of all the arguments, i.e., the elements of P, using P[number].

type U = P[number] // string | number | boolean

It is important to note that in the aforementioned example, P[0] corresponds to the type string, P[1] corresponds to the type number, and so forth.

However, direct usage of P[Number] is not feasible in the given context because our elements are promises and we need to extract their value types.

To facilitate this, we can introduce a helper type as follows:

type ValueType<T> = T extends Promise<infer U>
  ? U
  : T;

Upon receiving a Promise<T>, the aforementioned helper will yield T.

Finally, we integrate these strategies together:

const firstSettledValue = <P extends Promise<any>[]>(...promises: P): Promise<ValueType<P[number]>> => {
  const randomIndex = Math.floor(Math.random() * 100) % promises.length;
  return promises[randomIndex];
};

const v = firstSettledValue(
  Promise.resolve('Hello World'),
  Promise.resolve(15),
  Promise.resolve(false)
);

type ValueType<T> = T extends Promise<infer U>
  ? U
  : T;

Playground Link

At this juncture, v possesses the type

Promise<string | number | boolean>
, reflecting the promises specified during the call.

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

What steps should be taken to enable SCSS in Jest for unit testing in TypeScript Next.js?

I am facing an issue with the scss import in my project. I have attempted to solve it by using mockup and identity-obj-proxy, but neither of them seems to work. I suspect that there might be a problem with my regex expression. The specific error arises fr ...

Tips for continuously running a loop function until retrieving a value from an API within a cypress project

Need help looping a function to retrieve the value from an API in my Cypress project. The goal is to call the API multiple times until we receive the desired value. let otpValue = ''; const loopFunc = () => { cy.request({ method: &ap ...

Binding data to custom components in Angular allows for a more flexible

In my current scenario, I am looking to pass a portion of a complex object to an Angular component. <app-component [set]="data.set"></app-component> I want the 'data.set' object in the parent class to always mirror the 'set&apo ...

The Jest type definitions seem to be malfunctioning in this TypeScript project

Recently, I began a new Typescript project utilizing GTS. While the typings are functioning correctly for regular *.ts files, I am encountering difficulties in getting *.spec.ts files to work. Issue Each jest function is being flagged as red by ESLint wit ...

Issue with unapplied nullable type during export操作

I'm struggling to understand why my nullable type isn't being applied properly Here's an illustration interface Book { name: string; author: string; reference: string; category: string; } async function handleFetch<T>(endpoin ...

What is the process for importing a TypeScript module in the StackBlitz editor?

When I enter the editor at Stackblitz.com and start a new Angular project, it comes with default files and folders already set up. In the "Dependencies" section, I decide to add shortid. So, I input that in the designated box and it begins loading the cor ...

What steps should I take to import a module with type definitions? (receiving error TS2656: ...not a module)

I am currently working on enhancing the type definitions for a simple npm module called emitter20. The source code of this module spans 20 lines and looks like this: module.exports = function() { var subscribers = [] return { on: function (eventNa ...

Is the detection change triggered when default TS/JS Data types methods are called within an HTML template?

I'm currently updating an application where developers originally included function calls directly in the HTML templating, like this: <span>{{'getX()'}}</span> This resulted in the getX method being called after each change dete ...

The error TS2339 occurs because the property 'remove' is not found in the type 'Document<unknown>'

I encountered an error while using my application Runtime Error: TSError: ⨯ Unable to compile TypeScript: src/controllers/notes.ts:134:20 - error TS2339: Property 'remove' does not exist on type 'Document<unknown, {}, { createdAt: Nat ...

What should be the proper service parameter type in the constructor and where should it be sourced from?

Currently, I am faced with a situation where I have two Angular 1 services in separate files and need to use the first service within the second one. How can I properly type the first service in the constructor to satisfy TypeScript requirements and ensure ...

Reacting to the surprise of TS/JS async function behaving differently than anticipated

It appears that I'm facing a challenge with the small method; not sure if my brain is refusing to cooperate or what's going on. async fetchContacts() { await this.http.get('http://localhost:3000/contacts') .subscribe(res =& ...

Do TypeScript project references provide value when noEmit is used?

To enhance the speed of my editor interaction and reduce the time taken by tsc to run on my TypeScript code, I am considering implementing project references. Many teams have reported substantial performance improvements after incorporating project referen ...

Creating an Angular table using reactive forms: a step-by-step guide

After reviewing the HTML snippet provided below, it is evident that there is a table with looping through mat cell using *matCellDef="let model". Inside each cell, there are input fields which are reactive forms. Each row or cell needs to have it ...

Incapable of acquiring the classification of the attribute belonging to the

Is it possible to retrieve the type of an object property if that object is stored in a table? const records = [{ prop1: 123, prop2: "fgdgfdg", }, { prop1: 6563, prop2: "dfhvcfgj", }] const getPropertyValues = <ROW extends o ...

By specifying the union type being used, the TypeScript compiler is informed

Imagine I have the following type: type TMyType = { a: string; b: number; c: number; d?: SpecialTypeA | SpecialTypeB | SpecialTypeC; } How can I specify in typescript that I am aware of the type of d in my (React) child components? I am hoping f ...

A guide to resolving the Angular 11 error of exceeding the maximum call stack size

I am currently working with 2 modules in Angular 11 CustomerModule AccountingModule I have declared certain components as widget components in these modules that are used interchangeably: CustomerModule -> CustomerBlockInfoWidget AccountingModule -&g ...

I am attempting to store the primary array in local storage, but unfortunately, the value is not being saved within the React context API

I attempted to store the main array in local storage and retrieve it as global state, but I am facing an issue where the data is not being saved in the local storage. This file represents my context. import { createContext, useReducer, ReactNode, FC, use ...

Importing the isPropertyUpdated method in Angular 4

My challenge lies in utilizing the isPropertyUpdated function within Angular 4. However, I have encountered a roadblock as Angular 4 does not facilitate deep imports. An example of an import that fails to work on Angular 4 is: import {isPropertyUpdated} ...

Dealing with a situation where different functions need to be called based on a condition while using unique button names. This is

<button type="button" class="btn btn-primary ms-4" (click)="update()">Save</button> <button type="button" class="btn btn-primary ms-4" (click)="create()">Add</button> B ...

Installation and execution of TypeScript jQuery / Bootstrap definition file on a local machine using npm typings: A step-by-step guide

Struggling to set up TypeScript jQuery and Bootstrap definition files in my new project using npm typings. Below are the steps I followed: 1- Open cmd, navigate to my project folder, and enter the following commands: npm install typings --global typings ...