从泛型函数创建泛型类型

时间:2019-09-27 14:11:07

标签: typescript typescript-typings typescript-generics

我试图基于另一个通用类型声明一个通用类型,但没有成功。

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

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处找到游乐场。

谢谢!

1 个答案:

答案 0 :(得分:1)

如果我理解正确的话,您就很亲密。您可以在函数语法(在其中定义methodCall的签名,就好像您在定义函数实现那样)和属性语法(在其中将methodCall定义为恰好是lambda的属性)之间进行选择,这与您拥有的方式差不多)。

如果使用函数语法,请在尖括号(<>),括号之间的参数列表以及冒号后的返回类型中定义通用名称;就像您要定义的函数没有主体一样。如果使用属性语法,那么您将定义一个lambda,并在尖括号中加上通用名称,在括号之间添加参数列表,并在粗体箭头(=>之后的返回类型;您要通过该名称定义属性,并将类型-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