从泛型函数创建泛型类型

create generic type from generic function

我正在尝试基于另一个泛型类型声明一个泛型类型但没有成功。

objective是我自己编写的测试框架,并根据另一个框架(方法)键入一些参数。

type Arguments<T> = T extends (...args: infer U) => any ? U : never;

// my custom test method
const methodCall = <T extends (...args: any) => any>(args: {
  method: T;
  response: ReturnType<T>;
  myArguments: Arguments<T>;
}): boolean => {
  const { method, myArguments, response } = args;
  return method.apply(null, myArguments) === response;
};

const test1 = (toto: string) => {
  return toto === "success";
};

// usage of my custom function
methodCall({
  method: test1,
  myArguments: ["fail"],
  response: false
});


// this is what I want to type
interface MyHelpers {
  methodCall: any // HOW TO TYPE THIS? 
  methodCall2: (args: { flag: boolean }) => boolean;
}

// I would expose only the helpers object
const helpers = (): MyHelpers = {
  methodCall: <T extends (...args: any) => any>(args: {
    method: T;
    response: ReturnType<T>;
    myArguments: Arguments<T>;
  }): boolean => {
    const { method, myArguments, response } = args;
    return method.apply(null, myArguments) === response;
  },
  methodCall2: (args: { flag: boolean }): boolean => {
    return args.flag;
  }
};

我期待另一个调用助手的对象能够使用 helpers().methodCall(...) 进行键入,因为它在助手中声明。不适用于 any.

可以找到游乐场here

谢谢!

如果我没理解错的话,你已经很接近了。您可以在函数语法(定义 methodCall 的签名就像定义函数实现一样)和 属性 语法(定义 methodCall 为 属性 恰好是一个 lambda,这与你拥有它的方式很接近)。

如果使用函数语法,则在尖括号 (<>) 中定义泛型,在括号之间定义参数列表,冒号后的 return 类型;就好像你在定义一个没有主体的函数。如果使用 属性 语法,则定义了一个 lambda,泛型位于尖括号中,参数列表位于圆括号中,return 类型位于粗箭头之后(=>);您正在使用该名称定义 属性 并将您的类型 - a function type - 放在冒号之后。无论哪种方式都适合你。

(我还从您的自定义 Arguments 实用程序类型切换到 the undocumented Parameters built-in。)

interface MyHelpers {
  methodCall<T extends (...args: any) => any>(args: {
    method: T;
    response: ReturnType<T>;
    myArguments: Parameters<T>;
  }): boolean;
  methodCall2: (args: { flag: boolean }) => boolean;
}

interface MyHelpersWithObjectSyntax {
  methodCall: <T extends (...args: any) => any>(args: {
    method: T;
    response: ReturnType<T>;
    myArguments: Parameters<T>;
  }) => boolean;
  methodCall2: (args: { flag: boolean }) => boolean;
}

typescript playground