首页 > 解决方案 > 从泛型函数创建泛型类型

问题描述

我试图声明一个基于另一种泛型类型的泛型类型,但没有成功。

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

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.

操场可以在这里找到。

谢谢!

标签: typescripttypescript-typingstypescript-generics

解决方案


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

如果使用函数语法,则在尖括号 ( <>) 中定义泛型、括号之间的参数列表以及冒号后的返回类型;就好像您正在定义一个没有主体的函数。如果使用属性语法,则定义一个 lambda,尖括号中的泛型、括号之间的参数列表以及粗箭头 ( =>)后面的返回类型;您正在使用该名称定义属性并输入您的类型—<a href="https://www.typescriptlang.org/docs/handbook/functions.html#writing-the-function-type" rel="nofollow noreferrer ">一种函数类型——在冒号之后。无论哪种方式都适合你。

(我还从您的自定义Arguments实用程序类型切换到未记录的Parameters内置.)

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;
}

打字稿游乐场


推荐阅读