cincheo / jsweet

A Java to JavaScript transpiler.
http://www.jsweet.org
Other
1.46k stars 158 forks source link

Promise return type + overload = tsc compilation error on then #195

Closed lgrignon closed 7 years ago

lgrignon commented 7 years ago

This bug appeared recently and is probably irrelevant with tsc >= 2

return actionReturningPromise()
  .thenOnFulfilledThenableFunction(result -> {
    // blablabla
  });

transpiles to:

return this.actionReturningPromise()
  .then<any>((result) => {
     // blablabla
  });

which causes: error TS2347: Untyped function calls may not accept type arguments.

lgrignon commented 7 years ago

this error doesn't occur on my laptop, maybe a discrepancy in TS def files? Will take a deeper look later

lgrignon commented 7 years ago

Diving deeper into it, it appears that the problem is related to method overloading:

protected Promise<String> promptPopup(String popupTitle, String popupContent, String promptInputType) {
    return promptPopup(new IonicPopupPromptOptions() {
        {
            title = popupTitle;
            template = popupContent.replace("\n", "<br/>");
            okText = $translate.instant("OK");
            cancelText = $translate.instant("CANCEL");
            inputType = promptInputType;
        }
    });
}

protected Promise<String> promptPopup(IonicPopupPromptOptions options) {
    return new Promise<String>( //
            (CallbackBiConsumer<Consumer<String>, Consumer<Object>>) //
            (resolve, reject) -> {

                $ionicPopup.prompt(options)//
                        .thenSuccessCallbackFunction((Object response) -> {
                            resolve.accept((String) response);
                            return null;
                        }) //
                        .catchOnRejectedFunction(e -> {
                            reject.accept(e);
                            return null;
                        });
            });
}

transpiles to:

public promptPopup(popupTitle? : any, popupContent? : any, promptInputType? : any) : any {
    if(((typeof popupTitle === 'string') || popupTitle === null) && ((typeof popupContent === 'string') || popupContent === null) && ((typeof promptInputType === 'string') || promptInputType === null)) {
        let __args = Array.prototype.slice.call(arguments);
        return <any>(() => {
            return this.promptPopup(<any>Object.defineProperty({
                title: popupTitle,
                template: /* replace */popupContent.split("\n").join("<br/>"),
                okText: this.$translate.instant("OK"),
                cancelText: this.$translate.instant("CANCEL"),
                inputType: promptInputType
            }, '__interfaces', { configurable: true, value: ["def.ionic.ionic.popup.IonicPopupBaseOptions","def.ionic.ionic.popup.IonicPopupPromptOptions"] }));
        })();
    } else if(((popupTitle != null && (popupTitle["__interfaces"] != null && popupTitle["__interfaces"].indexOf("def.ionic.ionic.popup.IonicPopupPromptOptions") >= 0 || popupTitle.constructor != null && popupTitle.constructor["__interfaces"] != null && popupTitle.constructor["__interfaces"].indexOf("def.ionic.ionic.popup.IonicPopupPromptOptions") >= 0)) || popupTitle === null) && popupContent === undefined && promptInputType === undefined) {
        return <any>this.promptPopup$def_ionic_ionic_popup_IonicPopupPromptOptions(popupTitle);
    } else throw new Error('invalid overload');
}

promptPopup$def_ionic_ionic_popup_IonicPopupPromptOptions(options : IonicPopupPromptOptions) : Promise<string> {
    return <any>(new Promise<string>((resolve, reject) => {
        this.$ionicPopup.prompt(options).then<any>((response) => {
            resolve(<string>response);
            return null;
        }).catch<any>((e) => {
            reject(e);
            return null;
        });
    }));
}

any call to this method results in the following TS code:

this.promptPopup("blabla", "blibli", "input").then<any>((answer) => {
//...
});

which causes this not-so-understandable-error-message: error TS2347: Untyped function calls may not accept type arguments.

My opinion is that the any return type allows us to call any method and cast to any type but causes error if calling a generic method on it. So it would, in a way, be a TS problem rather than a JSweet problem, but IMO we could enhance the return type of overloaded methods.

lgrignon commented 7 years ago

Confirmed, this test doesn't compile:

var myPromise: any = new Promise((resolve, reject) => {});
myPromise.then<any>((pouet) => {  // compilation error: Untyped function calls may not accept type arguments. 
});
lgrignon commented 7 years ago

Enhance proposal : generates union for the return type corresponding to all the possible overload's return types.

In my example, that would be only "Promise", and if we add a String prompPopup(String), it would generate a return type of Promise | string

What do you think about it? Did I miss something?

renaudpawlak commented 7 years ago

I am closing since we are now using tsc 2.