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.
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
})
}
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?
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With