Promisifying a third-party JS library with minimal code overhead Context and Existing Code

I am trying to "promisify" a third-party authentication library (auth0-js) written in JavaScript. Right now it uses callback functions and there are no plans to expose an async/await friendly API. So, I'm writing a wrapper, to avoid callback hell in my own code.

Here's a callback factory function cb which is actively used for creating Promises.

import * as a0 from "auth0-js";

export function cb&lt;TResult&gt;(
  resolve: (reason: TResult) =&gt; void,
  reject: (reason: a0.Auth0Error) =&gt; void,
): a0.Auth0Callback&lt;TResult&gt; {
  return (error, result) =&gt; error ? reject(error) : resolve(result);
}


And here's an example of a wrapper class.

import * as a0 from "auth0-js";
import { cb } from "./cb";

export class Authentication {

  /**
   * Wraps the Auth0-js' `Authentication` object and exposes Promise-based methods.
   * @param wa Wrapped `Authentication` object.
   */
  constructor(private wa: a0.Authentication) { }

  public get dbConnection(): DbConnection {
    return new DBConnection(this.wa.dbConnection);
  }

  public buildAuthorizeUrl(options: any): string {
    return this.wa.buildAuthorizeUrl(options);
  }

  public loginWithDefaultDirectory(options: a0.DefaultDirectoryLoginOptions): Promise&lt;any&gt; {
    return new Promise((resolve, reject) =&gt; this.wa.loginWithDefaultDirectory(options, cb(resolve, reject)));
  }

  public login(options: a0.DefaultLoginOptions): Promise&lt;any&gt; {
    return new Promise((resolve, reject) =&gt; this.wa.login(options, cb(resolve, reject)));
  }

  public oauthToken(options: any): Promise&lt;any&gt; {
    return new Promise((resolve, reject) =&gt; this.wa.oauthToken(options, cb(resolve, reject)));
  }

  public loginWithResourceOwner(options: a0.ResourceOwnerLoginOptions): Promise&lt;any&gt; {
    return new Promise((resolve, reject) =&gt; this.wa.loginWithResourceOwner(options, cb(resolve, reject)));
  }

  public getSSOData(withActiveDirectories: boolean, options: a0.DelegationOptions): Promise&lt;any&gt; {
    return new Promise((resolve, reject) =&gt; this.wa.getSSOData(withActiveDirectories, cb(resolve, reject)));
  }

  public userInfo(accessToken: string): Promise&lt;a0.Auth0UserProfile&gt; {
    return new Promise((resolve, reject) =&gt; this.wa.userInfo(accessToken, cb(resolve, reject)));
  }

  public delegation(options: a0.DelegationOptions): Promise&lt;a0.Auth0DelegationToken&gt; {
    return new Promise((resolve, reject) =&gt; this.wa.delegation(options, cb(resolve, reject)));
  }

  public getUserCountry(): Promise&lt;{ countryCode: string; }&gt; {
    return new Promise((resolve, reject) =&gt; this.wa.getUserCountry(cb&lt;{ countryCode: string; }&gt;(resolve, reject)));
  }
}


Question

While I'm always open to any constructive feedback, there are a few specific aspects I'll be particularly thankful for.


I'm a C# developer and still know too little about JavaScript/TypeScript. If you know how to make this code look more JS-idiomatic, I'm all ears. Or I can paraphrase the question as "am I going the right/common route?"
You can see that there is a lot of structural repetition in the code that creates Promises from callbacks (e.g. loginWithDefaultDirectory(...), login(...), oauthToken(...) functions). Not nice. Is there a way to apply functional programming ideas here? I have a feeling that functional composition may get handy here, but I don't know how to apply it (a sign, I haven't grasp the concept yet)
Resolved It's also easy to notice that buildAuthorizeUrl(...) is a pass-through. No callbacks here. There must be an easier way to bind one object's function to another object's function, which I don't know how to do. Very similarly, get dbConnection() accessor is a supposed to be a pass-through.


Update 1

I figured the pass-through members can be coded very easily (one line per member):

 public buildAuthorizeUrl = this.wa.buildAuthorizeUrl;


So, point 3 is now out of question.
You are correct that you can avoid a lot of the structure duplication in this class. A promisify function would help a lot. Node has a built in util.promisify. Alternatively, you could write a simple method to apply the arguments and resolve when called. In vanilla JS this is simple enough. 

function callPromised(method, ...args) {
    return new Promise((resolve, reject) =&gt; {
        method(...args, (error, result) =&gt; error ? reject(error) : resolve(result))
    })
}


Unfortunately, this method is difficult to type correctly in TypeScript. There's a proposal here. The best we can do now is write several overloads which gets incredibly messy with only a few parameters.

function callPromised&lt;TResult&gt;(method: (cb: Auth0Callback&lt;TResult&gt;) =&gt; void): Promise&lt;TResult&gt;;
function callPromised&lt;TResult, Arg1&gt;(method: (arg1: Arg1, cb: Auth0Callback&lt;TResult&gt;) =&gt; void, arg1: Arg1): Promise&lt;TResult&gt;;
function callPromised&lt;TResult, Arg1, Arg2&gt;(method: (arg1: Arg1, arg2: Arg2, cb: Auth0Callback&lt;TResult&gt;) =&gt; void, arg1: Arg1, arg2: Arg2): Promise&lt;TResult&gt;;
function callPromised(method: Function, ...args: any[]): Promise&lt;any&gt; {
    return new Promise((resolve, reject) =&gt; {
        method(...args, (error, result) =&gt; error ? reject(error) : resolve(result))
    })
}


The downside of this function is that this will not be bound correctly. This could be rectified by passing in a self parameter and would be required for your usage.

function callPromised&lt;TResult&gt;(method: (cb: Auth0Callback&lt;TResult&gt;) =&gt; void, self: any): Promise&lt;TResult&gt;;
function callPromised&lt;TResult, Arg1&gt;(method: (arg1: Arg1, cb: Auth0Callback&lt;TResult&gt;) =&gt; void, self: any, arg1: Arg1): Promise&lt;TResult&gt;;
function callPromised&lt;TResult, Arg1, Arg2&gt;(method: (arg1: Arg1, arg2: Arg2, cb: Auth0Callback&lt;TResult&gt;) =&gt; void, self: any, arg1: Arg1, arg2: Arg2): Promise&lt;TResult&gt;;
function callPromised(method: Function, self: any, ...args: any[]): Promise&lt;any&gt; {
    return new Promise((resolve, reject) =&gt; {
        method.call(self, ...args, (error, result) =&gt; error ? reject(error) : resolve(result))
    })
}

// For example
public loginWithDefaultDirectory(options: a0.DefaultDirectoryLoginOptions): Promise&lt;any&gt; {
    return callPromised(this.wa.loginWithDefaultDirectory, this.wa, options)
}