Property 'allSettled' does not exist on type 'PromiseConstructor'.ts(2339)

JavascriptTypescriptEs6 Promise

Javascript Problem Overview


I'm trying to use the Promise.allSettled API with TypeScript. Code here:

server.test.ts:

it('should partial success if QPS > 50', async () => {
  const requests: any[] = [];
  for (let i = 0; i < 51; i++) {
    requests.push(rp('http://localhost:3000/place'));
  }
  await Promise.allSettled(requests);
  // ...
});

But TSC throws an error:

> Property 'allSettled' does not exist on type 'PromiseConstructor'.ts(2339)

I already added these values to the lib option in tsconfig.json:

tsconfig.json:

{
  "compilerOptions": {
    /* Basic Options */
    "target": "ES2015" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
    "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
    "lib": [
      "ES2015",
      "ES2016",
      "ES2017",
      "ES2018",
      "ES2019",
      "ES2020",
      "ESNext"
    ] 
   // ...
}

TypeScript version: "typescript": "^3.7.3"

So, how can I solve this? I know I can use an alternative module, but I am curious about working with TypeScript natively.

Javascript Solutions


Solution 1 - Javascript

The types for Promise.allSettled() were only merged in January, and will apparently be released in TypeScript 3.8.

As an interim solution, you can declare a mock-ish type for the function yourself:

declare interface PromiseConstructor {
    allSettled(promises: Array<Promise<any>>): Promise<Array<{status: 'fulfilled' | 'rejected', value?: any, reason?: any}>>;
}

Solution 2 - Javascript

To get this running on Linux, I needed the latest typescript version:

npm install -g typescript@latest

Then in your tsconfig you currently need the ES2020.Promise lib. My full tsconfig:

{
  "compilerOptions": {
    "sourceMap": true,
    "module": "commonjs",
    "target": "es5",
    "jsx": "react",
    "esModuleInterop": true,
    "allowJs": true,
    "outDir": "./dist",
    "lib": [
      "ES2020.Promise",
    ]
  },
  "include": [
    "./src"
  ],
  "exclude": [
    "./node_modules",
    "./build"
  ],
  "compileOnSave": true,
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    }
  }
}

Usage: const results = await Promise.allSettled(BatchOfPromises);

Solution 3 - Javascript

It's ES2020 and at Stage 4, so not available everywhere without a polyfill. It got typed and merged into TS. Try installing the latest @types/node package and see if that pulls it in.

Update: Looks like it will be adding es2020.promise to the libs, when it does land.

Update: npm i [email protected] woot woot!

Solution 4 - Javascript

Workaround to use it with older Typescript version

await (Promise as any).allSettled(promises);

Solution 5 - Javascript

There is a shim library available that provides identical functionality (https://www.npmjs.com/package/promise.allsettled), but note that it requires an explicit import (var allSettled = require('promise.allsettled');).

If you are working in typescript, the equivalent typed package is https://www.npmjs.com/package/@types/promise.allsettled, but note that the type names do not match the official ES2020 implementation, so if you want an exact drop-in replacement, you will need to add a new TS file to alias the types and make available in the global namespace:

import { PromiseRejection, PromiseResolution, PromiseResult } from 'promise.allsettled';

// https://stackoverflow.com/a/59499895/323177
export {}

// TechDebt: Remove once project is migrated to ES2020
// Global type aliases are required because the promise.allsettled shim doesn't match the types of the actual 
// ES2020 implementation
declare global {
    export type PromiseFulfilledResult<T> = PromiseResolution<T>;
    
    export type PromiseRejectedResult = PromiseRejection<any>;
    
    export type PromiseSettledResult<T> = PromiseResult<T, any>;

    export class PromiseConstructor {
        /**
         * Creates a Promise that is resolved with an array of results when all
         * of the provided Promises resolve or reject.
         * @param values An array of Promises.
         * @returns A new Promise.
         */
         allSettled<T extends readonly unknown[] | readonly [unknown]>(values: T):
             Promise<{ -readonly [P in keyof T]: PromiseSettledResult<T[P] extends PromiseLike<infer U> ? U : T[P]> }>;

        /**
         * Creates a Promise that is resolved with an array of results when all
         * of the provided Promises resolve or reject.
         * @param values An array of Promises.
         * @returns A new Promise.
         */
        allSettled<T>(values: Iterable<T>): Promise<PromiseSettledResult<T extends PromiseLike<infer U> ? U : T>[]>;
    }
}

Solution 6 - Javascript

What worked for me was to simply add "es2020" into the "lib" attribute of tsconfig.json file

tsconfig.json file with the value

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionslideshowp2View Question on Stackoverflow
Solution 1 - JavascriptAKXView Answer on Stackoverflow
Solution 2 - JavascriptLeigh MathiesonView Answer on Stackoverflow
Solution 3 - JavascriptJosh WulfView Answer on Stackoverflow
Solution 4 - JavascriptDevil SparrowView Answer on Stackoverflow
Solution 5 - JavascriptWoodzView Answer on Stackoverflow
Solution 6 - JavascriptRamón EspinosaView Answer on Stackoverflow