ptmn ptmn - 1 month ago 14
TypeScript Question

Unwrapping a Promise object in Typescript/JavaScript

I am novice in JavaScript/TypeScript Promise return type.

The problem is I am hosting a rest API endpoint which internally invokes another API from a different service that returns a Promise object using JS Request module.

I want to unwrap the internal API promise response and create a new normal Typescript object and finally return the new modified response object rather than a Promise.

Here is a sample code to describe my problem:

export class SampleClass {
public process(): NewResponse {
const newResponse: NewResponse = new NewResponse();
// invokeOtherAPI() call Returns a Promise by invoking a different endpoint
invokeOtherAPI().then(function (result) {
newResponse.propertyOne = result.propertyOne;
newResponse.propertyTwo = result.propertyTwo;
});
return newResponse;
}}


In this case the process() returns an empty value though it gets assigned inside the then().

Here is my controller class for the REST API (Path decorators are missing)

export class SampleController() {
const service: SampleClass = new SampleClass();
public get(): NewResponse {
return service.process();
}
}


Questions:


  1. Is it a good practice to return the Promise object all the time from a Typescript API?

  2. Is there a way I can unwrap a promise object internally and return a non promise object from an API?



Thanks for any help on this.

Answer Source

I want to unwrap the internal API promise response and create a new normal Typescript object and finally return the new modified response object rather than a Promise.

You can't. If any part of your API function is asynchronous, then the whole API has to be asynchronous which means it has to either return a promise which the caller uses .then() or await on to get the value out of or you use the older style callback and the caller passes in a callback which you call when the asynchronous value is available.

There's a fair amount more explanation here: How do I return the response from an asynchronous call?.

  1. Is it a good practice to return the Promise object all the time from a Typescript API?

Yes. If the operation is asynchronous, then returning a promise is a desirable way to communicate back the asynchronous result.

  1. Is there a way I can unwrap a promise object internally and return a non promise object from an API?

No. You could use the older callback style to communicate back the result if you really didn't want to use promises, but the caller is left with the same issue of dealing with an asynchronous result and you can't return the result directly from your API.


In this code:

export class SampleClass {
 public process(): NewResponse {
    const newResponse: NewResponse = new NewResponse();
    // invokeOtherAPI() call Returns a Promise by invoking a different endpoint
    invokeOtherAPI().then(function (result) {
        newResponse.propertyOne = result.propertyOne;
        newResponse.propertyTwo = result.propertyTwo;
    });
    return newResponse;
}}

Things go wrong as the line where you do return newResponse. At that point, newResponse does not yet have a value. The ONLY place you know it has a value is inside the .then() handler. This is why you can't return the result directly from your API. Your API will return BEFORE the value has been retrieved. That's exactly what promises are for. You return the promise and the caller uses .then() on that returned promise to get the value.

I don't know the TypeScript way to do this myself so you can fill in the proper syntax for the return value, but this is returning the promise here:

export class SampleClass {
 public process(): <fill in promise return value type here> {
    const newResponse: NewResponse = new NewResponse();
    // return promise from this function
    return invokeOtherAPI().then(function(result) {
        newResponse.propertyOne = result.propertyOne;
        newResponse.propertyTwo = result.propertyTwo;
        // make newResponse be the resolved value of the promise
        return newResponse;
    });
}};