简体   繁体   English

如何从 Typescript 的参数列表中返回函数的 ReturnType?

[英]How can I return the ReturnType of functions from a list of parameters in Typescript?

I have a main function myMainFunction() that takes in a list of functions as parameters.我有一个主函数myMainFunction() ,它接收函数列表作为参数。 Each of these parameter functions can have a different return type.这些参数函数中的每一个都可以有不同的返回类型。

I would like myMainFunction have its return type as the return types of the functions passed into it as parameters.我希望myMainFunction将其返回类型作为作为参数传递给它的函数的返回类型。 However, I can't quite figure out to do it.但是,我不知道该怎么做。

Here's what I have which doesn't seem to work:这是我所拥有的似乎不起作用的东西:

const funcA = async (): string => "Hello";
const funcB = async (): {name: string, age: number} => ({ name: "Jane", age: 123 });

const myMainFunction = async <F extends () => ReturnType<F>>(...functions: F[]): Promise<ReturnType<F>[]> => {
  const res = await Promise.all(functions.map((fn) => fn()));
  return res;
};

// This doesn't work as values has a type of Promise<string>[]
// I'm expecting values to have a type of Promise<[string, {first: string, age: number }]>
const values = await myMainFunction(funcA, funcB);

What I have above doesn't work as the the variable values has a type of Promise<string>[] .我上面的内容不起作用,因为变量values的类型是Promise<string>[] For some reason, it only sees the return type of the first function in the parameters.由于某种原因,它只看到参数中第一个函数的返回类型。

I'm expecting that values will have type of Promise<[string, {first: string, age: number }]> which are essentially the return types of funcA() and funcB() .values的类型为Promise<[string, {first: string, age: number }]> ,它们本质上是funcA()funcB()的返回类型。

How can I achieve it?我怎样才能实现它?

Typescript has a special type for Array types T[number] , so using this we can do-> Typescript 对数组类型T[number]有一个特殊的类型,所以我们可以使用它->

const funcA = async (): Promise<string> => "Hello";
const funcB = async (): Promise<{name: string, age: number}> => ({ name: "Jane", age: 123 });

const myMainFunction = async <T extends any[number][]> (...functions: T) => {
  const res = await Promise.all(functions);
  return res;
};

async function test() {
    const values = await myMainFunction(funcA(), funcB());
    // values[0]  string
    // values[1]  {name: string, age: number}
    console.log(values[1].age);
}

Typescript Playground 打字稿游乐场

The problem when you pass the functions, the map function loses the Type.传递函数时的问题,映射函数会丢失类型。 But we could just put them back in using as .但是我们可以把它们放回去使用as Thanks to @TJCrowder I used his MapToUnpromisedReturnType helper type and got this ->感谢@TJCrowder,我使用了他的 MapToUnpromisedReturnType 辅助类型并得到了这个 ->

const funcA = async (): Promise<string> => "Hello";
const funcB = async (): Promise<{name: string, age: number}> => ({ name: "Jane", age: 123 });

type MapToUnpromisedReturnType<T extends Array<any>> = {
    [K in keyof T]: Awaited<ReturnType<T[K]>>;
};

const myMainFunction = async <T extends (() => Promise<any[number]>)[]> (...functions: T) => {
  const mapped = await functions.map(f => f());
  return mapped as MapToUnpromisedReturnType<T>;
};

async function test() {
    const values = await myMainFunction(funcA, funcB);
    // values[0]  string
    // values[1]  {name: string, age: number}
    console.log(values[1].age);
}

Playground 2. passing promise functions Playground 2. 传递promise函数

ps: there may be a cleaner way, but it does seem to work nicely.. ps:可能有更清洁的方法,但它似乎工作得很好..

Just a slightly refactored version to take away helper ->只是一个稍微重构的版本来带走助手->

const myMainFunction = async <T extends (() => Promise<any[number]>)[]> (...functions: T) => {
  return functions.map(f => f()) as {[K in keyof T]: Awaited<ReturnType<T[K]>>};
};

Refactored 重构

Old and not so clean version, don't use.旧的和不那么干净的版本,不要使用。

type ResolveFunction<T extends (...args: any) => any> = Awaited<ReturnType<T>>;
type ResolveFunctions<T extends [...((...args: any) => any)[]]> = T extends [
  infer Head,
  ...infer Tail
]
  ? Head extends (...args: any) => any
    ? Tail extends ((...args: any) => any)[]
      ? [ResolveFunction<Head>, ...ResolveFunctions<Tail>]
      : []
    : []
  : [];

const myMainFunction = async <T extends [...((...args: any) => any)[]]>(
  ...functions: T
): Promise<ResolveFunctions<T>> => {
  const res = await Promise.all(functions.map((fn) => fn()));
  return res as any;
};

New version after looking at another answer.查看另一个答案后的新版本。

type AsyncFunction = (...args: any) => Promise<any>;
type ResolveFunction<T extends AsyncFunction> = Awaited<ReturnType<T>>;
type ResolveFunctions<T extends AsyncFunction[]> = {
  [K in keyof T]: ResolveFunction<T[K]>;
};

const myMainFunction = async <T extends AsyncFunction[]>(
  ...functions: T
): Promise<ResolveFunctions<T>> => {
  const res = await Promise.all(functions.map((fn) => fn()));
  return res as any;
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM