2
votes

I'm trying to build an MVC like controller in TypeScript and I'm having difficulty getting my async method to return a deferred promise.

Here's my function signature:

static async GetMatches(input: string, loc?: LatLng):JQueryPromise<any> {

The compiler tells me that a 'JQueryPromise' is not a valid async function return type.

I would have thought that something like this would be the most common use case for an async function but I can't find any examples.

Any help?

3
Is this still applicable to jQuery 3 (from what I've read it's supposed to be Promises/A+ compliant)?rink.attendant.6
I don't know I'm afraid. I stopped using jQuery not long after this post. I just found it easier to code in vanilla js / typescript insteadCraig Poole

3 Answers

3
votes

From the issue detailing async functions (I found no better reference):

An Async Function must provide a return type annotation that points to a compatible Promise type. Return type inference can only be used if there is a globally defined, compatible Promise type.

and then

Async Functions require a compatible Promise abstraction to operate properly. A compatible implementation implements the following interfaces, which are to be added to the core library declarations (lib.d.ts):

interface IPromiseConstructor<T> {  
    new (init: (resolve: (value: T | IPromise<T>) => void, reject: (reason: any) => void) => void): IPromise<T>;  
}  

interface IPromise<T> {  
    then<TResult>(onfulfilled: (value: T) => TResult | IPromise<TResult>, onrejected: (reason: any) => TResult | IPromise<TResult>): IPromise<TResult>;  
}

jQuery deferreds are - for good reasons - not on their compatibility list.

2
votes

JQueryPromise does not satisfy the requirements for the promises made by async/await, they should inplement the following interfaces:

interface IPromiseConstructor<T> {  
    new (init: (resolve: (value: T | IPromise<T>) => void, reject: (reason: any) => void) => void): IPromise<T>;  
}  

interface IPromise<T> {  
    then<TResult>(onfulfilled: (value: T) => TResult | IPromise<TResult>, onrejected: (reason: any) => TResult | IPromise<TResult>): IPromise<TResult>;  
}

For more details see section 4 Promise here: link

2
votes

To enable async/await for jQuery promises, use the following. It works in combination with jquery.d.ts from DefinitelyTyped.

class JQueryPromise<T> {
    constructor(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) {
        let dfd = $.Deferred<T>();
        function fulfilled(value?: T | PromiseLike<T>) {
            let promise = <PromiseLike<T>>value;
            if (value && promise.then) {
                promise.then(fulfilled, rejected);
            }
            else {
                dfd.resolve(<T>value);
            }
        }
        function rejected(reason) {
            let promise = <PromiseLike<T>>reason;
            if (reason && promise.then) {
                promise.then(fulfilled, rejected);
            }
            else {
                dfd.reject(<T>reason);
            }
        }
        executor(fulfilled, rejected);
        return dfd.promise();
    }
}

Example:

interface IData {
  value: number;
}

async function getValue(): JQueryPromise<number> {
    let result = <IData> await $.getJSON('/data.json');
    return result.value;
}