Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

typescript how to unwrap/remove Promise from a type?

i have a function that accepts an object where each prop is a promise. it waits for all the promise to finish then returns a new object with the same props but now resolved values.

enter image description here

resolved_props.company should be string, not Promise<string>

// TODO: fix the types on this
function promise_props<T>(obj:T):Promise<T> {
  const keys = Object.keys(obj)
  const len = keys.length
  const awaitables = new Array<T>(len)
  for (var i = 0; i < len; i++) awaitables[i] = (obj as any)[keys[i]]

  return Promise.all(awaitables).then((results) => {
    const byName:any = {}
    for (var i = 0; i < len; i++) byName[keys[i]] = results[i]
    return byName
  })
}
like image 761
Farzher Avatar asked Feb 23 '18 09:02

Farzher


People also ask

How do you return a promise in typescript?

Promise accepts a callback function as parameters, and in turn, the callback function accepts two other parameters, resolve and reject. If the condition is true, then resolve is returned; else, returns reject. Basically, the return type of Promise type is defined immediately after the keyword Promise. How does TypeScript Promise type work?

What are the advantages of using promises in JavaScript?

One good thing about the Promise type is that it can understand the flow of values through the promise chain. Users can provide the data type of the value returned whenever the promise type is fulfilled.

What is the difference between resolve and reject in typescript?

If the function’s response is a success, then it will return ‘resolve’; if the response from the function is not successful, it will return ‘reject’. 3. States available in promise of Typescript: Promise support several states.

What is the return type of return function in typescript?

Return type: It has two parameters inside the inner function. If the function’s response is a success, then it will return ‘resolve’; if the response from the function is not successful, it will return ‘reject’. 3. States available in promise of Typescript: Promise support several states.


1 Answers

Your types are not accurate enough and the TypeScript compiler cannot figure it out that they are not promises at that point.

What you need is something like this:

async function promise_props<T>(obj: {[key: string]: Promise<T>}): Promise<{[key: string]: T}> {
    const keys = Object.keys(obj);
    const awaitables = keys.map(key => obj[key]);

    const values = await Promise.all(awaitables);
    const result: {[key: string]: T} = {};

    keys.forEach((key, i) => {
        result[key] = values[i];
    });
    return result;
}

But it will only work if your object has promises of the same type, for example:

{
    company: Promise.resolve("company"),
    page: Promise.resolve("1")
};

I'm not sure if it is possible to get it working with various promise types in the current TypeScript version, but as Tao also suggested, you can use the new features in TypeScript 2.8 to get it working:

type UnPromisifiedObject<T> = {[k in keyof T]: UnPromisify<T[k]>}
type UnPromisify<T> = T extends Promise<infer U> ? U : T;

async function promise_props<T extends {[key: string]: Promise<any>}>(obj: T): Promise<UnPromisifiedObject<T>> {
    const keys = Object.keys(obj);
    const awaitables = keys.map(key => obj[key]);

    const values = await Promise.all(awaitables);
    const result = {} as any;

    keys.forEach((key, i) => {
        result[key] = values[i];
    });
    return result as UnPromisifiedObject<T>;
}

async function main() {
    const x = {
        company: Promise.resolve("company"),
        page: Promise.resolve(1)
    };
    const res = await promise_props(x);
    const company = res.company;  // company is a string here
    const page = res.page;        // page is a number here
}

As you can see, the return type is properly inferred. I think the implementation of the method can be improved. I couldn't find a way to instantiate an instance of the return type and use any, but although compiler cannot infer it, it's type safe as we resolve all promises.

like image 98
Wickoo Avatar answered Oct 21 '22 04:10

Wickoo