Creating a TypeScript dynamic array that contains promises with varying return types

Is there anyone out there who can assist me in figuring out what's causing problems with this piece of code? I'm struggling to determine the correct type to use in that Promise.all call at the end. I attempted using

Promise.all<Services[], PullRequests[]>(ops)
but it seems like PullRequests[] cannot be optional...

function wait<Twait>(time: number, response: Twait): Promise<Twait> {
    return new Promise(resolve => setTimeout(() => resolve(response), time))
}

interface Service {
    name: string;
    id: number;
}

async function getServices(): Promise<Service[]>  {
    const response = await wait(400, { "id": 200 });
    return [{ name: "service", id: response.id }]
}


interface PullRequest {
    prType: string;
    githubId: number;
}

async function getPrs(): Promise<PullRequest[]>  {
    const response = await wait(400, { "githubId": 200 });
    return [{ prType: "foo", githubId: response.githubId }]
}


async function main(): Promise<void> {

    const ops: [ PromiseLike<Service[]>, PromiseLike<PullRequest[]>? ] = [getServices()]

    if (Math.random() > 0.5) { // <== this is random on purpose.
        ops.push(getPrs())
    }
    
    
    const [ services, prs ] = await Promise.all(ops) // This throws a ts compile error (attached below)
    console.log("services:")
    console.log(services)
    console.log("prs:")
    console.log(prs)    
}

No overload matches this call. The last overload gave the following error.
 Argument of type '[PromiseLike<Service[]>, (PromiseLike<PullRequest[]> | undefined)?]' is not assignable to parameter of type 'Iterable<Service[] | PromiseLike<Service[] | undefined> | undefined>'. 
The types returned by '[Symbol.iterator]().next(...)' are incompatible between these types. 
Type 'IteratorResult<PromiseLike<Service[]> | PromiseLike<PullRequest[]> | undefined, any>' is not assignable to type 'IteratorResult<Service[] | PromiseLike<Service[] | undefined> | undefined, any>'. 
Type 'IteratorYieldResult<PromiseLike<Service[]> | PromiseLike<PullRequest[]> | undefined>' is not assignable to type 'IteratorResult<Service[] | PromiseLike<Service[] | undefined> | undefined, any>'. 
Type 'IteratorYieldResult<PromiseLike<Service[]> | PromiseLike<PullRequest[]> | undefined>' is not assignable to type 'IteratorYieldResult<Service[] | PromiseLike<Service[] | undefined> | undefined>'. 
Type 'PromiseLike<Service[]> | PromiseLike<PullRequest[]> | undefined' is not assignable to type 'Service[] | PromiseLike<Service[] | undefined> | undefined'. 
Type 'PromiseLike<PullRequest[]>' is not assignable to type 'Service[] | PromiseLike<Service[] | undefined> | undefined'. 
Type 'PromiseLike<PullRequest[]>' is not assignable to type 'PromiseLike<Service[] | undefined>'. 
Type 'PullRequest[]' is not assignable to type 'Service[]'. 
Type 'PullRequest' is missing the following properties from type 'Service': name, id

Answer №1

It appears there is a common issue in TS library definitions, as mentioned in microsoft/TypeScript#28427. The problem lies in the hardcoded specific tuple types within the library that do not account for optional elements. Efforts have been made to address this, but due to complexities with PromiseLike types and their interaction with await, none of the pull requests addressing this issue have been accepted yet. A comment in microsoft/TypeScript#39788 states that changing this could potentially disrupt existing code relying on current definitions.

Until this matter is resolved upstream, one can utilize declaration merging to include a custom signature for Promise.all(), which simply maps promise unwrapping across elements of the array or tuple being passed:

interface PromiseConstructor {
  all<T extends readonly any[]>(
    values: { [K in keyof T]: T[K] | PromiseLike<T[K]> }
  ): Promise<T>;
}

You can then test if it functions as intended:

const promiseAllOps = Promise.all(ops); // no error now
// const promiseAllOps: Promise<[Service[], (PullRequest[] | undefined)?]>
const awaitPromiseAllOps = await promiseAllOps;
// const awaitPromiseAllOps: [Service[], (PullRequest[] | undefined)?]
const [services, prs] = awaitPromiseAllOps;
services; // Service[]
prs; // PullRequest[] | undefined

Playground link

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

The argument provided is a string type, which cannot be assigned to a parameter expecting an object with a 'results' property of type string

When attempting to pass the result.nativeEvent.message to another function, I am encountering the error: Argument of type 'string' is not assignable to parameter of type '{ results: string; } on onUnityMessageController(result.nativeEvent.me ...

Utilizing numeric values linked to strings within an associative array

Looking for help with a card deck array: $cards = array("2_of hearts" => 2, "3_of_hearts" => 3, "king_of_hearts" => 10); I'm trying to display the card name (e.g., 2_of_hearts) and perform some calculations with the associated number, but I ...

NextImage encountering issues in Internet Explorer 11

In my TypeScript setup, here is a snippet from my package.json file: "dependencies": { "@tailwindcss/typography": "^0.4.1", "@webcomponents/shadydom": "^1.7.4", "cookie": "^0.4.1", " ...

Tips for preventing <v-layouts> from impacting one another

I'm currently working on a dynamic link box for a homepage website, which can be viewed at . Inside this link box, I have included a button that allows the creation of buttons that function as links. Interestingly, the layouts of both the options but ...

Struggling to grasp the concept of async/await and promises

I'm fairly new to working with node.js and JavaScript in general. I've been trying to understand promises and async/await concepts, specifically in the context of requesting images from a remote URL asynchronously and converting them to base64 fo ...

Optimizing File Transfers and Streaming Using Next.js and CDN Integration

As I work on developing a download system for large files on my website using Next.js and hosting the files on a CDN, I face the challenge of downloading multiple files from the CDN, creating a zip archive, and sending it to the client. Currently, I have i ...

Retrieve the row with the lowest score using PHP

My PHP array is structured like this: $array = array( array( 'mark' => 10, 'name' => 'name 1', ), array( 'mark' => 15, 'name' => 'name ...

Struggling to create a functioning toggle button using jQuery in a React application

I've encountered an issue with my react web application. I'm trying to implement a voting system where clicking the like button changes its color and functionality, allowing it to be liked only once. If clicked again, it should return to a neutra ...

Reset the select boxes when a button is clicked

I'm currently utilizing Devextreme within my Angular application, and I have three dx-selectbox elements in the component. I am attempting to clear all three dropdown selections when clicking a "clear" button. Unfortunately, I am unable to find a way ...

Nested within a foreach loop is a while loop in PHP

In the given code snippet, the line $find_cond = str_replace('|',' ',$rem_exp); fetches 225 and 245 numbers. I am aiming to retrieve records based on these two ID numbers. However, the current implementation of the code is producing re ...

Exploring SimpleXML by iterating through every element

I received a stock report file from an external source, and I need to iterate over all elements in order to save them into a MySQL table. The $xml->Stockfile seems to be an array of objects with 2 items, so I attempted to store it in an array. However, ...

Caution when populating an array with IBOutlet buttons

Struggling to organize 9 buttons in an array, facing the error message: Cannot use instance member 'oneOne' within property initializer; property initializers run before 'self' is available I encountered this error with each button. ...

Step-by-step guide on importing CSS into TypeScript

I have a global CSS file where I've defined all the colors. I attempted to import that value into TypeScript but it didn't work. This is my latest attempt: get sideWindowStyle(): any { switch (this.windowStyle) { case 'classicStyl ...

Changing NSData to Java String

I am currently working on an iOS application that utilizes a web service built in Java. The app sends a POST request to the web server with an NSData object, created from a JSON, which looks something like this: <7b22636c 69656e74 223a7b22 656e7669 726 ...

What is the process for creating static pages that can access local data within a NextJS 13 application?

I recently completed a blog tutorial and I must say, it works like a charm. It's able to generate dynamic pages from .md blog posts stored locally, creating a beautiful output. However, I've hit a roadblock while attempting what seems like a sim ...

Python Script to Extract Hyperlinks from HTML Documents

I am in the process of developing a Python script to extract the iframe src from a given set of websites. For example, if my input includes A.com, B.com, and C.com, and each of these sites has iframes linking to D.com, E.com, F.com (or 'None' if ...

Utilizing Typescript to extract data from a database according to the input provided by the user

Trying to fetch data from Database based on user input. Below is a snapshot of the DB for reference. https://i.sstatic.net/iMRup.png In my frontend, I have a dropdown that displays names from the database. Upon selection, I need to retrieve the correspon ...

Converting data in MongoDB arrays

As a beginner with MongoDB, I am attempting to transform the data within each document using the provided information. Any assistance in completing this task would be greatly appreciated. getconvaggregate1 collection:(existing) { "_id&qu ...

Using the spread operator on the left side of an assignment to gather all remaining elements of an array into one variable by destructuring

I'm looking to implement Destructuring in php similar to the javascript code snippet below: [a, b, ...rest] = [10, 20, 30, 40, 50]; console.log(a,b,rest); Expected Output: 10 20 [ 30, 40, 50 ] Is there a way to achieve this functionality in php? Th ...

Breaking up assignments in a loop with Angular's *ngFor

Having issues while attempting to iterate through a JavaScript dictionary within my HTML markup using *ngFor with Object.entries, and encountering an error message: Error: Unexpected token [, expected identifier, keyword, or string at column 5 in [let ...