Skip to content

Instantly share code, notes, and snippets.

@DScheglov
Created March 3, 2023 18:51
Show Gist options
  • Save DScheglov/b6c4021e2d12cbd590f1ae3b26504167 to your computer and use it in GitHub Desktop.
Save DScheglov/b6c4021e2d12cbd590f1ae3b26504167 to your computer and use it in GitHub Desktop.
propsResolver
type AnyResolvers = {
[prop in PropertyKey]: (params: any) => any
}
type Resolved<R extends AnyResolvers> = {
[prop in keyof R]: Awaited<ReturnType<R[prop]>>
}
type UnionToIntersection<U> = (U extends any ? (a: U) => any : never) extends ((b: infer A) => any) ? A : never;
type Params<R extends AnyResolvers> = UnionToIntersection<{
[prop in keyof R]: Parameters<R[prop]> extends [] ? {} : Parameters<R[prop]>[0]
}[keyof R]>
const allNames = <T extends {}>(obj: T) => [
...Object.getOwnPropertyNames(obj) ,
...Object.getOwnPropertySymbols(obj),
] as Array<keyof T>;
const isPromise = (value: any): value is Promise<unknown> => typeof value?.then === "function";
const then: {
<T, R>(value: T, callback: (v: T) => R): R;
<T, R>(value: Promise<T>, callback: (v: T) => R): Promise<Awaited<R>>
} = <T, R>(
value: T | Promise<T>,
callback: (v: T) => R,
) => isPromise(value) ? value.then(callback) : callback(value);
const propsResolver = <R extends AnyResolvers>(resolvers: R) =>
(params: Params<R>): Promise<Resolved<R>> => {
const result = {} as Resolved<R>;
return Promise.all(allNames(resolvers).map(
prop => then(
resolvers[prop](params),
propResult => { result[prop] = propResult; }
)
)).then(() => result)
}
/// ======= Usage =======
const getData = propsResolver({
x: ({ xId }: { xId: number }) => Promise.resolve(xId),
y: ({ yId }: { yId: string }) => Promise.resolve(yId),
z: () => 1 as const,
});
async function main() {
const value = await getData({ xId: 1, yId: "2" });
console.log(value);
type T = {
[p in keyof typeof value]: (typeof value)[p]
}
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment