Say I have an object like so:
export const v = {
a() : Promise<X>{
},
b() : Promise<Y>{
},
c() : Promise<Z>{
}
}
my question is - is there any way to get the type of v, but map the type, so that it looks something like this:
export type V = {
a: X,
b: Y,
c: Z
}
basically I am mapping each key in the object, to the resolved value of the respective promise.
Basically, I am trying to derive a modified type, from something that's declared statically.
You can do this using conditional types and mapped type:
class X{}
class Y{}
class Z{}
export const v = {
a() : Promise<X>{
return null as any;
},
b() : Promise<Y>{
return null as any;
},
c() : Promise<Z>{
return null as any;
},
}
type ExtractAllPromisses<T> =
{
// Take all keys of T ([P in keyof T])
// and if the property P of T is a promise returning function (T[P] extends ()=> Promise<infer U>)
// then the new type of P will be the return type of the promise (saved in U)
// Otherwise the new type of P is never
[P in keyof T]: T[P] extends ()=> Promise<infer U> ? U : never
};
export type V = ExtractAllPromisses<typeof v> // same as type V = { a: X; b: Y; c: Z; }
There are variations you can do in the conditional type depending on your need, the example above works specifically for a type which has just functions that take no arguments and return a Promise
If you want to match a function with any number of arguments you can use:
type ExtractAllPromisses<T> = { [P in keyof T]: T[P] extends (...args: any[])=> Promise<infer U> ? U : never };
If your type also has properties that are not promise returning functions and you want to preserve those properties (ie v
also has a field foo:number
) you can use:
type ExtractAllPromisses<T> = { [P in keyof T]: T[P] extends (...args: any[])=> Promise<infer U> ? U : T[P] };
If you want to exclude properties that are not a promise retuning function. You can filter the keys:
type PromiseFunctionFields<T> = { [P in keyof T] : T[P] extends (...args: any[])=> Promise<any> ? P : never}[keyof T];
type ExtractAllPromisses<T> = { [P in PromiseFunctionFields<T>]: T[P] extends (...args: any[])=> Promise<infer U> ? U : T[P] };