Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bluebird 3.0 definifion is not assignable to ES6 Promises #11027

Closed
Strate opened this issue Sep 5, 2016 · 48 comments
Closed

bluebird 3.0 definifion is not assignable to ES6 Promises #11027

Strate opened this issue Sep 5, 2016 · 48 comments

Comments

@Strate
Copy link
Contributor

Strate commented Sep 5, 2016

The bluebird 3.0 definition is not assignable to standard es6 Promise definition:

Types of property 'then' are incompatible.
Type 'Bluebird<any>' is not assignable to type 'Promise<any>'.

/cc @lhecker

@lhecker
Copy link
Contributor

lhecker commented Sep 5, 2016

@Strate Can you post the remaining output of tsc? And please try to open your local bluebird.d.ts and add this single line from #10831. Does that fix your issue?

@Strate
Copy link
Contributor Author

Strate commented Sep 5, 2016

Whole error:

error TS2322: Type '(entity: BaseEntity) => Bluebird<{ contentType: "ActivityDesktopWidget" | "AddressType" | "Approv...' is not assignable to type 'UpdateEntityFunction<BaseEntity>'.
  Type 'Bluebird<{ contentType: "ActivityDesktopWidget" | "AddressType" | "Approval" | "BaseIntegrationEn...' is not assignable to type 'Promise<BaseEntity>'.
    Types of property 'then' are incompatible.
      Type '{ <U>(onFulfill: (value: { contentType: "ActivityDesktopWidget" | "AddressType" | "Approval" | "B...' is not assignable to type '{ <TResult1, TResult2>(onfulfilled: (value: BaseEntity) => TResult1 | PromiseLike<TResult1>, onre...'.
        Type 'Bluebird<any>' is not assignable to type 'Promise<any>'.

I am using typescript@2.0.0 with lib.es2016.d.ts file. Adding that line does not help.

@lhecker
Copy link
Contributor

lhecker commented Sep 5, 2016

Ah I see... I believe it's due to this line missing here. This means with the current typings you have to return the same type U from both onFulfill as well as onReject. It'd be super cool if someone could fix this in the npm and this dt repository btw.

In the meantime you should probably split up your .then(success, failure) into .then(success).catch(failure) since that is probably what you did right? While it's part of the official syntax it's really not the "preferred" one with bluebird anyways though.

The alternative is that you could manually specify the generic parameter U like this

.then<SomeType>(() => new SomeType(), (err) => 123); // This is an explicit error because SomeType != number

to ensure that you return the same type from both callbacks.

@Strate
Copy link
Contributor Author

Strate commented Sep 5, 2016

@lhecker but I don't even use then or catch. I have something like that:

// module 1. Note that bluebird is not imported
export default function<T>(promise: Promise<T>) {} // es6 promise used here

// module 2.
import Promise from "bluebird"
import handler from "./module1"
const promise: Promise<any>
handler(promise) // <-- error is here

@Strate
Copy link
Contributor Author

Strate commented Sep 5, 2016

Seems that it could be fixed by adding yet another then declaration, compatible with es6's one to bluebird.d.ts

@lhecker
Copy link
Contributor

lhecker commented Sep 5, 2016

Ah damn... sorry. I guess I should finally take a break. 😅

So ignore my comments about what to do in the meantime: Since they are missing anyways and since I really don't or at least "should not" have the time for doing anything besides basic support like this, it'd be greatly appreciated if you could send PRs to add those typings to both projects. 😊

@Strate
Copy link
Contributor Author

Strate commented Sep 5, 2016

@lhecker done :)

@blakeembrey
Copy link
Member

blakeembrey commented Sep 6, 2016

Just a side note, but I always recommend using PromiseLike for when you accept promises. It will guarantee the minimum implemented promise interface so you can accept most promises. Then you can return the promise type of your chosing, making it stricter like Bluebird<T> which has many extra methods. For a long while, none of my promises were assignable because of the ES6 symbols being added to ES6 promise types.

@Strate
Copy link
Contributor Author

Strate commented Sep 6, 2016

@blakeembrey using PromiseLike in this case is not the answer, because PromiseLike also has incompatible version of then

@Strate Strate closed this as completed Sep 7, 2016
@OliverJAsh
Copy link
Contributor

Unfortunately the Promise typings have changed in TS version 2 and so these typings no longer correspond: https://github.com/Microsoft/TypeScript/blob/070aa83cc06b2974639bbefcde98e6e2fb5fe693/src/lib/es2015.promise.d.ts

Can we re-open this issue?

@gabzim
Copy link
Contributor

gabzim commented Oct 2, 2016

Any updates on this?

@Strate
Copy link
Contributor Author

Strate commented Oct 2, 2016

@OliverJAsh @arg20 could you guys provide self-reproduceable test case of your issue?

@jmendiara
Copy link

jmendiara commented Oct 2, 2016

@Strate here you have my error. Using typescript 2.0.3 (lib.es6.d.ts) and @types/bluebird v3.0.33

error TS2345: Argument of type 'Bluebird<Db>' is not assignable to parameter of type 'Promise
<Db>'.                                                                                                            
  Types of property 'then' are incompatible.                                                                      
    Type '{ <U1, U2>(onFulfill: (value: Db) => U1 | Thenable<U1>, onReject: (error: any) => U2 | Thenable<U...' is
 not assignable to type '{ <TResult1, TResult2>(onfulfilled: (value: Db) => TResult1 | PromiseLike<TResult1>, onre
jected: ...'.                                                                                                     
      Type 'Bluebird<any>' is not assignable to type 'Promise<any>'.                                              
        Types of property 'then' are incompatible.                                                                
          Type '{ <U1, U2>(onFulfill: (value: any) => U1 | Thenable<U1>, onReject: (error: any) => U2 | Thenable<.
..' is not assignable to type '{ <TResult1, TResult2>(onfulfilled: (value: any) => TResult1 | PromiseLike<TResult1
>, onrejected:...'.                                                                                               
            Type 'Bluebird<any>' is not assignable to type 'Promise<any>'.              

@jmendiara
Copy link

jmendiara commented Oct 2, 2016

Trying to cast the Bluebird Promise to an ES6 promise throws the following (bluebirdPromise as Promise<Db>)

 error TS2352: Type 'Bluebird<Db>' cannot be converted to type 'Promise<Db>'.                 
  Types of property 'then' are incompatible.                                                                      
    Type '{ <U1, U2>(onFulfill: (value: Db) => U1 | Thenable<U1>, onReject: (error: any) => U2 | Thenable<U...' is  not comparable to type '{ <TResult1, TResult2>(onfulfilled: (value: Db) => TResult1 | PromiseLike<TResult1>, onrejected: ...'.                                                                                                     
      Type 'Bluebird<any>' is not comparable to type 'Promise<any>'.                                              
        Property '[Symbol.toStringTag]' is missing in type 'Bluebird<any>'.         

@jmendiara
Copy link

adding this as proposed in #10831 worked for me

readonly [Symbol.toStringTag]: 'Promise';

also, converting to a ES6 Promise did the trick

return new Promise.resolve(bluebirdPromise)

@Strate
Copy link
Contributor Author

Strate commented Oct 2, 2016

@jmendiara as stated in #10831, there is no readonly [Symbol.toStringTag] in bluebird actually, so, adding this to bluebird.d.ts is definetely wrong: typings should represent real world.
If Promise standard require readonly [Symbol.toStringTag], it should be added to bluebird itself and bluebird.d.ts too. Seems that you should definetely use conversion between bluebird and native promises (which is really annoying).
FYI: you can use Promise.resolve without new keyword.

@Strate
Copy link
Contributor Author

Strate commented Nov 4, 2016

Just ran into issue when bluebird's promise is not assignable to standard one. And in my case it is impossible to cast bluebird to standard with Promise.resolve, because it is deep in 3rd party object. So, sometimes it is reasonable to have bluebird's promise to be assignable to standard one without conversion.
Just created feature request in bluebird's repository, to add Symbol.toStringTag to bluebird's instances.

petkaantonov/bluebird#1277

@RaulTsc
Copy link
Contributor

RaulTsc commented Apr 7, 2017

Any updates on this?

@yankeeinlondon
Copy link

Glad I found this thread. Thought I was going nuts. Would really like to see a fix for this. I described my problem specifics on SO

@silentorb
Copy link

I'm running into this issue with @types/bluebird 3.5.3 and TypeScript 2.2.2.

@yankeeinlondon
Copy link

yankeeinlondon commented Apr 28, 2017

@silentorb I have got this working by using the @types/bluebird-global type definition and then overriding the global promise definition (which you'll have if you're targeting an ES2015 platform) by adding the following to the top of my code execution entrypoint:

import * as Promise from 'bluebird';
global.Promise = require('bluebird');

The above works for node environment (I'm using 6.10.x). If you're using webpack then you may need to use something like expose-loader.

@silentorb
Copy link

@ksnyde: I previously tried out @types/bluebird-global and ran into multiple missing Promise details. I considered patching @types/bluebird-global but it would be better to have @types/bluebird working.

@yankeeinlondon
Copy link

@silentorb the key is to override the global Promise reference; works without issue for me. That said, it certainly would be nice if it just worked out of the box but there's no need to wait with this solution.

@JustBlackBird
Copy link

Any progress on this?

@lhecker
Copy link
Contributor

lhecker commented Jul 12, 2017

@flyingsky (et. al.) First of all I'd like to remind everyone again that it will never ever be possible to directly assign native Promises to Bluebird ones, since Bluebird promises provide extensions which do not exist in the native implementation.

Assigning Bluebird promises to native ones on the other hand should be possible and rightly so. But many here are under the impression that this should just work right now, which definitely is not the case.

The reason for this is that while Bluebird exposes all commonly known functions in a native compatible way, it does not expose one particular field: The [Symbol.toStringTag] field has to be "promise". See here: petkaantonov/bluebird#1277. This makes Bluebird strictly seen incompatible with native promises. Soo...

const p: any = getPromise();
return <Promise>p;

This is technically type unsafe and incorrect.

I considered patching @types/bluebird-global, but it would be better to have @types/bluebird working.

bluebird-global serves an entirely different use case than bluebird does: It exists in case you go the very much type unsafe route of overwriting the global Promise variable with Bluebird. (It's unsafe because simply overwriting it does not mean that every package you depend on won't continue using native promises.)

If anyone in this issue wants to see progress I kindly suggest opening a PR for the already mentioned Bluebird issue: petkaantonov/bluebird#1277

@kara-ryli
Copy link
Contributor

If anyone in this issue wants to see progress I kindly suggest opening a PR for the already mentioned Bluebird issue: petkaantonov/bluebird#1277

Looks like this PR has been created: petkaantonov/bluebird#1421

@mikol
Copy link

mikol commented Mar 21, 2018

@ksnyde – Your @types/bluebird-global suggestion works for me, slightly modified:

import * as Promise from 'bluebird'
global.Promise = Promise

Otherwise I get error TS6133: 'Promise' is declared but its value is never read. Which is expected for tsconfig.json with "noUnusedLocals": true.

Thank you.

@mmiszy
Copy link
Contributor

mmiszy commented Dec 27, 2018

I'm using bluebird-global but still get this error:

Property '[Symbol.toStringTag]' is missing in type 'Bluebird'

Adding this line fixes the issue https://github.com/DefinitelyTyped/DefinitelyTyped/pull/10831/files

Is there any way to fix it locally without modifying bluebird's typings?

@anasanzari
Copy link

+1

@lhecker
Copy link
Contributor

lhecker commented Apr 14, 2019

@gdpaulmil Thanks for your constructive comment!

It prompted me to take a look at the state of affairs over at Bluebird.
Turns out petkaantonov/bluebird#1421 was merged 11 days ago, meaning they finally added support for Symbol.toStringTag! 🎉

This in turn means this problem can be fixed right away by resubmitting #10831. One will only have to swap out "Promise" with "Object". I'd honestly review it right away. 🙂

@dancrumb
Copy link
Contributor

dancrumb commented May 10, 2019

@lhecker, created #35353 to get this all cleared up!

RyanCavanaugh pushed a commit that referenced this issue May 24, 2019
…34805)

* [bluebird] Rename import to Bluebird for tests

* [bluebird] Restore assignability to native Promises

* [bluebird] Upgrade TypeScript Versions of all dependents
@lhecker
Copy link
Contributor

lhecker commented May 24, 2019

Hey, I'd just like to let you all know that this issue has been fixed in v3.5.27 of @types/bluebird.
You may now enjoy being able to assign all these Bluebirds to all these Promises. 🎉
You'll have to use TypeScript 3.2 or newer for this though. (See #34805)

P.S.: Thanks again @JoshuaKGoldberg for dealing with the Bluebird PR. 🙂👍

@VictorioBerra
Copy link

Is:

import * as Promise from 'bluebird';
global.Promise = require('bluebird');

Still applicable for es2017?

@jacklinton
Copy link

Except for all the other packages that have the previous version as a dependency and didn't get the memo... request-promise, knex,... you just broke a lot of code with this update. The Typescript compiler is throwing nonsense errors all over the place, Typescript 3.3, 3.4, 3.5... doesn't seem to matter.

@VictorioBerra
Copy link

If it helps anyone, as mentioned higher up I had the easiest time just NOT swapping my global Promise object out for BB. I haven't encountered any issues where one thing was compatible with another thing.

@lhecker
Copy link
Contributor

lhecker commented Jun 3, 2019

@jacklinton I'm sure you are already aware that unit tests are in place to verify that all affected packages still build with the given TypeScript version without "throwing nonsense errors".
For instance here's a project that shows request-promise working with the newest Bluebird typings: https://github.com/lhecker/request-promise-sample
Since I can't reproduce your issue it'd be awesome if you could provide a minimal example which shows the issues you're seeing.

@jacklinton
Copy link

It's difficult to know where to begin, but with all other packages up to date
Error:(19, 3) TS2741: Property '[Symbol.toStringTag]' is missing in type 'Bluebird<string[]>' but required in type 'Bluebird<string[]>'.
If I remove @types/bluebird these errors go away. The only conjecture I can make with the time I have is that not all other packages that need these types have caught up yet. I Suspect Knex is a likely culprit, but I don't know. It grabs its own dependency of the previous version of this package.

@lhecker
Copy link
Contributor

lhecker commented Jun 3, 2019

This error does sound as if you got two versions of @types/bluebird installed. You should try and see whether you can flatten that tree so that you only have one of them.

knex 0.17.3 depends on the newest 3.5.27 version of the @types/bluebird typings btw. If you have an up-to-date version of knex it should actually work I suppose.
Same goes for your your second copy of @types/bluebird though: It should also be 3.5.27.

@jacklinton
Copy link

Thanks for being responsive @lhecker . I didn't mean to sound critical, I apologize. You've clearly been working hard on this and it's something we've all been waiting a long time for. Thanks for your hard work getting this update out so quickly after Bluebird made the change. I'll get this bloated monolith to work the way it's supposed to one way or another.

iRON5 pushed a commit to iRON5/DefinitelyTyped that referenced this issue Aug 13, 2019
…Typed#11027) (DefinitelyTyped#34805)

* [bluebird] Rename import to Bluebird for tests

* [bluebird] Restore assignability to native Promises

* [bluebird] Upgrade TypeScript Versions of all dependents
@bennycode
Copy link
Contributor

@lhecker can you please republish your request-promise-sample because it seems to be gone. 😢

@VictorioBerra the trick with

import * as Promise from 'bluebird';
global.Promise = require('bluebird');

gives me to following error on Node.js 12:

global.Promise = Promise;
Type 'typeof Bluebird' is missing the following properties from type 'Function': apply, call, bind, length, and 4 more.

I am using TypeScript v3.7.4, bluebird v3.7.2 and @types/bluebird-global v3.5.12.

@lhecker
Copy link
Contributor

lhecker commented Jan 21, 2020

@bennyn I don't have the code anymore. I'm very sorry. I deleted it after the request-promise issue was fixed.
Make sure you use the latest version of @types/bluebird at 3.5.29.

@rodrigoreis22
Copy link

I'm having the same error as @bennyn , with the latest versions of all bluebird, @types/bluebird-global and TypeScript

@chebum
Copy link
Contributor

chebum commented Mar 20, 2020

It seems the only viable option with current version of Bluebird 3.7.2 and TypeScript 3.6 is not to use Bluebird typings at all.

At the app entrypoint I replace native Promise constructor with Bluebird and use Bluebird using native promise API after that:

import * as Bluebird from "bluebird";
global.Promise = Bluebird;

new Promise((resolve, reject) => {
  // this is actually a Bluebird object
});

@lhecker
Copy link
Contributor

lhecker commented Mar 20, 2020

I personally, frankly, believe that you guys are doing something wrong on your end. 😖
I've reconstructed my minimal request-promise-sample project which shows how you absolutely 100% definitely can...

  • assign the Bluebird constructor to global.Promise
  • use request-promise without compilation errors
  • assign Bluebird class instances to the Promise interface (which is what this issue is about)

That said, this issue has been closed and should not be used for continued off-topic discussions.
The above discussion is off-topic, as this ticket is about Bluebird promises not being assignable to ES6/native Promises. But as shown above this issue has long been fixed.
If you have trouble using @types/node@13.x.x with Bluebird please see #42084 instead.

@chebum
Copy link
Contributor

chebum commented Mar 21, 2020

@lhecker
Thank you for the reply. I tried your project and it also doesn't work:
Annotation 2020-03-21 084422

Installing @types/node@13.x.x doesn't help either:
Annotation 2020-03-21 084750

Modified project can be found here:
https://github.com/chebum/request-promise-sample

@lhecker
Copy link
Contributor

lhecker commented Mar 21, 2020

@chebum Your comment above didn't make clear that you're trying to type async functions as ones returning a Bluebird<T>. In that case I could've already told you that this isn't possible unfortunately. As you can see by the output of your compiler you must return a Promise<T> type from an async function.

If you'd like to waive a little bit of your type safety you can do the following though:

  1. Add @types/bluebird-global as dependency
  2. Override the global Promise constructor: window.Promise = Bluebird as any;
  3. Write: async function testFn(): Promise<void>
  4. The global Promise<T> type is now almost identical to Bluebird<T> and you should be able to use all important Bluebird features.

If you hit any Symbol.species errors etc. please do not use this ticket but rather #42084.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests