请考虑一组具有不同参数的简单函数:
const fns = {
isValidDate: (input: string, min?: Date, max?: Date): boolean => {
// ...
return true;
},
isValidOption: (input: string, options: string[]): boolean => {
// ...
return true;
},
};
它们都返回相同的类型(bool);
然后是另一个函数,该函数应该调用上述任何函数:
function validateField(where: string, fn: keyof typeof fns, ...args: any[]){
// ...
return fns[fn](...args);
}
怎样才能使args
反映出所选fn
的参数呢?
例如:
validateField("test", "isValidDate", new Date()); // should be ok
validateField("test", "isValidDate", 123); // should fail
并让参数显示在vscode提示中,就像一般函式一样。
我知道我需要为每个fn
创建validateField
重载,但如何使用类型定义或其他方法来实现这一点...而不必手动定义每个重载并使用这些参数编写重复的代码
2条答案
按热度按时间gmxoilav1#
您可能希望
validateField()
在fn
参数的类型中为generic,这样您就可以为args
选择合适的类型。我们可以编写一些辅助实用程序类型来计算它:FnArgs
类型是mapped类型,其中每个键都来自fns
类型,并且每个值都是初始string
之后的参数元组(使用条件类型推断来获得该列表)。现在,您可以为
validateField()
指定以下调用签名:当您调用它时,它将工作:
不幸的是,
validateField()
的实现没有类型检查:根本问题是缺少对microsoft/TypeScript#30581中所请求的 *correlated union * 的直接支持。编译器无法理解
fns[fn]
的类型是与args
的类型相关的函数类型。错误消息有点晦涩,但它来自于这样的事实,即它将args
视为不适合于fns[fn]
的自变量的元组类型的并集,它将fns[fn]
视为没有公共rest参数类型的函数类型的并集。幸运的是,在microsoft/TypeScript#47109中有一个推荐的解决方案。我们需要给予
fns
一个新的类型,编译器一眼就能看到这个类型是一个对象,它的方法的参数与FnArgs
直接相关。下面是它的外观:_fns
变量被注解为方法的Map类型,对于Fns
的键中的每个K
都显式使用类型为FnArgs[K]
的rest参数。fns
对该变量的赋值成功,因为它是相同的类型。但关键的区别在于
_fns[fn](where, ...args)
成功,而fns[fn](where, ...args)
失败,这是因为编译器跟踪了_fns[fn]
类型和args
类型之间在泛型K
中的相关性。现在,您就拥有了对调用者和函数实现都能按预期工作的东西!
Playground代码链接
s4n0splo2#
要解决您的问题,可以使用泛型类型获取函数类型,然后使用此类型获取参数的类型