Bluebird: Typescript support

Created on 26 Aug 2014  路  19Comments  路  Source: petkaantonov/bluebird

There are typings files for bluebird on DefinitelyTyped (which I'm about to add to since they're still for version 1.0.0). However, the promisify/promisifyAll() function does not work out of the box with TypeScript as it changes the typing of a library at run-time. Is there any experience / guidelines on working with promises and TypeScript? I'm currently back to extensive use of the Promise constructor, which appears not to be the recommended way to go.

Most helpful comment

So is there now a generator/tool which read the "callback" *.d.ts of module to promisify and produce an async *.d.ts file to merge definition and provide intelisense for promisyfied code?

This is a really great idea. I might try and hack on it when I get some time...

All 19 comments

ping @spion

@rogierschouten first - note that promisify/promisifyAll run during the program's execution and dynamically generate a function - it relies on the fact JS engines are JITed. The way I see it you have two options - you can either generate d.ts files manually (or better - generate them) or you can look into promisify.js and replicate it - effectively generating a .ts file at compile time from those APIs.

Generally speaking, you can assume that whenever you have a:

function foo(param1:Type1, param2:Type2, nodeback: () -> (errRetType, retType)) -> ()

The signature of fooAsync generated by calling promisifying foo - preserving all type information would be:

function fooAsync(param1:Type1, param2:Type2) -> Promise<errRetType, retType>

Although more realistically you don't want to care about your errRetType in your Promise<T> (unless you're a Java checked exceptions fan since that would be your analogy).

Its impossible to produce type definition for promisifyAll in TypeScript - typescript's type system simply isn't powerful enough.

Lets hope that the github version of the compiler gets an official API - then we might be able to write a tool that automatically generates the second type signature in @benjamingr's post from the first.

Thanks guys, that's what I thought. Will see if/when I can make a (d).ts generator that is powerful enough for most cases for the meantime.

Just a quick note that with the new typescript ES6 module syntax, the older import style syntax plays havok, As the Promise.resolve(blah) no longer works as it complains about generics being required, but if you were to try to put generics in it blows up as it doesnt understand how you are going to use it (as its a static object).

I put an issue up on definitely typed.
https://github.com/borisyankov/DefinitelyTyped/issues/5289

So not sure if the descriptors need an update or there is some other workaround available.

If you want to import it as Promise, you want import * as Promise from 'bluebird' - or alternatively, use bluebird.resolve(...)

On the other hand, that makes new Promise impossible to use. However bluebird also exports Promise as a property on itself, therefore (if the appropriate .d.ts file is written) you could do

edit: this was wrong, import * as Promise from 'bluebird' seems to work just fine.

tried the former syntax still requires a generic

This works fine here:

import * as Promise from 'bluebird'

function fn(s:string | Promise<string>) {
    return Promise
            .resolve(s)
            .then(parseFloat);
}

with latest typescript version (1.5.3 on npm) I get:

(13,24): error TS2314: Generic type 'Promise<R>' requires 1 type argument(s).

Cannot reproduce the issue. Can you please make a minimal example with steps to reproduce?

LOL ok so while 99% through replicating it on Cloud9 I realised the issue.

Which was down to I was returning the promise, but was not providing the type at the point of return, and that was throwing the error not the point of using the static:

https://ide.c9.io/grofit/typescript-bluebird-issue

There is a simple use case anyway, you can ignore it and I will go back to my cave :)

Everything worked out fine then :)

I was surprised that the definitions work with the new ES6 module syntax though. It doesn't work when importing typescript files that define export = SomeClass but apparently its fine for modules declared by definition files.

Yeah, thanks for the help. Although my issue is fixed I am not sure if the descriptor being updated to use the new ES6 export syntax is something worth thinking about or not.

I just ran over this (original issue) as well and may have found a work around which seems to enable me to use promisify on overloaded functions in typescript.

My original code was:

private static readFilePromise = Promise.promisify(fs.readFile);
readFilePromise(path, 'utf8').then(...);

Where it complained:

error TS2346: Supplied parameters do not match any signature of call target.

I changed the definition of readFilePromise to:

private static readFilePromise:(filename: string, encoding: string)=>Promise<string> 
  = <(...all:any[])=>any>(Promise.promisify(fs.readFile));

This is a little bit hacky, but seems to work for me. Not sure if it would be wise to change the definition on DefinitelyTyped such that promisify returns (...all:any[])=>any, because then you loose the Typings completely unless you cast it to the call signatures you want.

So is there now a generator/tool which read the "callback" *.d.ts of module to promisify and produce an async *.d.ts file to merge definition and provide intelisense for promisyfied code?

the same issue here

error TS2346: Supplied parameters do not match any signature of call target.

fixed with bit hacky solution

const hash: (data: string, salt: string, callback: (error: Error, result: string) => void) => Bluebird<{}>
  = Bluebird.promisify(bcrypt.hash);

So is there now a generator/tool which read the "callback" *.d.ts of module to promisify and produce an async *.d.ts file to merge definition and provide intelisense for promisyfied code?

This is a really great idea. I might try and hack on it when I get some time...

I just cast as any or use bracket/string.
Totally "works" though I lose intelisense.

//this all works:
import xml2js = require('xml2js');
import Promise = require('bluebird');
Promise.promisifyAll(xml2js);

//options 1: cast as any
(xml2js as any).parseStringAsync( haveto, knowThisSignatureByHeart)
//would be nice if it knew the "Async" suffix just got added to parseString() method, so I didn't have to do this.

//bracket/string reference
xml2js"parseStringAsync"
//I suppose this is nice if you manage that hardwired method name string, so maybe slightly better.

Hi, there are a guide to use bluebird as replacement for native promise in typescript server app ? i read many tricks or hacks but i still have typescript compilation errors.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

chrisprobst picture chrisprobst  路  5Comments

rainabba picture rainabba  路  5Comments

julien-f picture julien-f  路  5Comments

overlookmotel picture overlookmotel  路  5Comments

divramod picture divramod  路  5Comments