yBother
yBother

Reputation: 718

Angular using promise with generics inside promise

I need to interlace promises in my app:

  protected scroll<T>(path: string, pageSize: number, filter: string, data: T[]): Promise<T[]> {    
            let promise = new Promise<T[]>(function(resolve, reject) {
                this.httpClient
                    .get<T[]>(this.appConfigService.buildApiUrl(path), { params })
                    .toPromise<T[]>()
                    .then(result => {
                        if (result) {
                            resolve(data.concat(result));
                        }
                    })
                    .catch(function(e) {
                        reject(e);
                    });
            });

            return promise;
        }

My problem is that I receive following message: 'Untyped function calls may not accept type arguments'

How would I solve this?

UPDATE:

I should not have removed the if condition from the example:

  if (!filter) {
            const params = new HttpParams()
                .set('searchText', '')
                .set('skip', data.length.toString())
                .set('take', pageSize.toString());

            const promise = new Promise<T[]>((resolve, reject) => {
                this.httpClient
                    .get<T>(this.appConfigService.buildApiUrl(path), { params })
                    .toPromise<any>()
                    .then(result => {
                        if (result) {
                            resolve(data.concat(result));
                        }
                        resolve(data);
                    })
                    .catch(e => reject(e));
            });

            return promise;
        }
        // also returning a promise
        return this.filter<T>(data, pageSize, filter, path);

Upvotes: 0

Views: 158

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074058

There are a couple of problems there.

  1. The error message is because you're using <T[]> on get and toPromise, which aren't generic functions. Just apply the type T to result in the then handler.

  2. You're falling into the promise creation antipattern. You already have a promise (from this.httpClient), so you don't need new Promise.

  3. You're using a traditional function for your new Promise callback, but then using this within it as though it were still referring to your class instance. If you were going to keep the new Promise, you'd want an arrow function instead, so it closes over this.

Instead (see *** comments):

protected scroll<T>(path: string, pageSize: number, filter: string, data: T[]): Promise<T[]> {    
    // *** Return the result of calling `then` on the promise from `toPromise`
    return this.httpClient
        // *** Don't use <T[]> on `get` and `toPromise`
        .get(this.appConfigService.buildApiUrl(path), { params })
        .toPromise()
        .then((result: T) => { // *** <== Note the `T`
            // *** If it's really possible that `result` will be falsy and you don't want that
            // to be valid, you can do this:
            if (!result) {
                throw new Error("appropriate error here");
            }
            return data.concat(result);
        });
}

On the playground


UPDATE:

I should not have removed the if condition from the example:

It doesn't matter, just put the body of the above into the if block:

protected scroll<T>(path: string, pageSize: number, filter: string, data: T[]): Promise<T[]> {    
    if (!filter) {
        const params = new HttpParams()
           .set('searchText', '')
           .set('skip', data.length.toString())
           .set('take', pageSize.toString());

        return this.httpClient
            // *** Don't use <T[]> on `get` and `toPromise`
            .get(this.appConfigService.buildApiUrl(path), { params })
            .toPromise()
            .then((result: T) => { // *** <== Note the `T`
                // *** If it's really possible that `result` will be falsy and you don't want that
                // to be valid, you can do this:
                if (!result) {
                    throw new Error("appropriate error here");
                }
                return data.concat(result);
            });
    }
    return this.filter<T>(data, pageSize, filter, path);
}

Upvotes: 1

Related Questions