ES6 Promise / Typescript and the Bluebird Promise
Asked Answered
I

3

17

I have a nodejs / typescript 2 project and use the es6-promise package. Now i would like to get rid of the extra package because i can target ES6 in typescript directly.

So i removed the es6-promise package and changed the tsconfig.json to target es6.

{
  "compilerOptions": {
    "target": "es6",
    // ...
  }
}

Many 3rd party packages uses the Bluebird promise but the promise definition is incompatible to the default es6 promise as stated on different posts on github

So i am getting the following error.

TS2322: Type 'Bluebird' is not assignable to type 'Promise'. Property '[Symbol.toStringTag]' is missing in type 'Bluebird'.

There is a other types package on npm @types/bluebird-global. In one of the blog post a user suggests to use it instead of @types/bluebird but some 3rd party packages (e.g. sequelize typings) reference bluebird and not bluebird-global so i get another error for the missing typings of bluebird.

What is a good solution to get this to work?

Improvident answered 9/3, 2017 at 7:57 Comment(3)
Can you try to put: interface Bluebird { [Symbol.toStringTag]: string } in a file bluebird-patch.d.ts?Subsequent
Thanks but this does not work for me.Improvident
In the end these packages are returning you Bluebird promises so you should include Bluebird package and definition files to your project. Trying to "rename" bluebird promise "Promise" like they are native Promise could be really confusing (even tho' they have the same API) Plus I don't see anyway to do this. :)Dillie
B
6

I was dealing with

TS2322: Type 'Bluebird' is not assignable to type 'Promise'. Property '[Symbol.toStringTag]' is missing in type 'Bluebird'.

and found this thread: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/10801

The TL;DR; version of it is to do one of the following:

  1. In each of your .ts entry files add the following to overwrite the global promise:

    import * as Bluebird from 'bluebird';

    declare global { export interface Promise<T> extends Bluebird<T> {} }

Or

  1. wrap all promises in a Bluebird promise constructor. There is some runtime overhead here and it is listed as an anti pattern on Bluebird's site.

As an aside, I could not get the second option to work, but the first worked fine for me.

Buckboard answered 2/1, 2018 at 15:40 Comment(0)
S
4

Since there is no [Symbol.toStringTag] in Bluebird, it's incompatible indeed. There are other things that differ Bluebird implementation from native Promise - scheduler, error handling... The correct way to handle this is:

const promise: Promise<type> = Promise.resolve<type>(bluebirdPromise);

If runtime compatibility is not an issue for sure, this can be addressed with type casting only in relatively type-safe manner:

const promise: Promise<type> = <Promise<type>><any><Bluebird<type>>bluebirdPromise;

or

const promise: Promise<type> = <Promise<type>><PromiseLike<type>>bluebirdPromise;
Selfacting answered 6/9, 2017 at 19:54 Comment(0)
P
0

To avoid this error, I add async to the function that returns a Bluebird promise.

Example:

async myFunction(items){
   return Bluebird.map( items, (item) => {
      ...
   })
}
Pulido answered 15/8 at 11:37 Comment(1)
How is this different from the existing answers which already mention wrapping the Bluebird Promise in a native Promise?Frankel

© 2022 - 2024 — McMap. All rights reserved.