Typescript 使用不同数量的泛型参数创建重载时出现问题

Typescript 使用不同数量的泛型参数创建重载时出现问题,typescript,generics,Typescript,Generics,此简化代码的最初目的是在typescript中创建一个通用方法,该方法接收委托和对象,并返回一个新委托,其签名应与传入委托相同,但“this”上下文将成为传入对象 作为伪代码,它应该是这样的: f(del(args:…参数),context)=>del(this:typeof context,args:…参数) 我尝试了一些方法,但都失败了 下面的代码似乎是最有希望的尝试,但最终也失败了 在代码中,我强调了我的问题。基本上,typescript编译器无法根据methodWithDelegate函

此简化代码的最初目的是在typescript中创建一个通用方法,该方法接收委托和对象,并返回一个新委托,其签名应与传入委托相同,但“this”上下文将成为传入对象

作为伪代码,它应该是这样的: f(del(args:…参数),context)=>del(this:typeof context,args:…参数)

我尝试了一些方法,但都失败了

下面的代码似乎是最有希望的尝试,但最终也失败了

在代码中,我强调了我的问题。基本上,typescript编译器无法根据methodWithDelegate函数的签名自动推断arg1和arg2的类型

有什么解释吗

有解决办法吗

function createDelegate<TContext extends Object, TReturn, A>(fn: (a: A) => TReturn, context: TContext): (this: TContext, a: A) => TReturn
function createDelegate<TContext extends Object, TReturn, A, B>(fn: (a: A, b: B) => TReturn, context: TContext): (this: TContext, a: A, b: B) => TReturn
function createDelegate<TContext extends Object, TReturn, A, B, C>(fn: (a: A, b: B, c: C) => TReturn, context: TContext): (this: TContext, a: A, b: B, c: C) => TReturn
function createDelegate<TContext extends Object, TReturn, A, B, C>(instance: any, funct: Function): any
{
    return <any>funct.bind(instance);
}

function methodWithDelegate(delegate: (this: string, val1: string, val2: string) => void)
{
    //delegate invokation
}

methodWithDelegate(function (val1, val2)
{
    // OK. val1 and val2 are inferred to be strings.
     val1.substring(2);
});

methodWithDelegate(createDelegate(function (val1, val2)
{
    // ISSUE: val1 and val2 are not inferred to be strings. they remain of type any
    val1.substring(2);
}, "CONTEXT"));
函数createDelegate(fn:(a:a)=>TReturn,context:TContext:(this:TContext,a:a)=>TReturn
函数createDelegate(fn:(a:a,b:b)=>TReturn,context:TContext:(this:TContext,a:a,b:b)=>TReturn
函数createDelegate(fn:(a:a,b:b,c:c)=>TReturn,context:TContext:(this:TContext,a:a,b:b,c:c)=>TReturn
函数createDelegate(实例:any,函数:function):any
{
返回funct.bind(实例);
}
函数methodWithDelegate(委托:(this:string,val1:string,val2:string)=>void)
{
//委托调用
}
methodWithDelegate(函数(val1,val2)
{
//好的。val1和val2被推断为字符串。
val1.子串(2);
});
methodWithDelegate(createDelegate)(函数(val1,val2)
{
//问题:val1和val2不会被推断为字符串。它们仍然是任意类型
val1.子串(2);
}(“上下文”);

关于为什么会发生这种情况,我没有一个很好的答案。你可能想提出一个问题,要求解释。毫无疑问,泛型类型参数推断、函数参数推断和重载解析之间存在一些相互作用

显然,一种解决方法就是将
val1
val2
的类型指定为
string
。。。也就是说,放弃复杂的推理游戏,明确地要求你需要什么:

methodWithDelegate(createDelegate(function(val1: string, val2: string): void {
  val1.substring(2);
}, "CONTEXT"));
在我看来,这样做显式注释是一种好的做法,因为我更喜欢陈述我的意图,而不是依赖编译器的推断(可能不正确)。但我知道你更喜欢别的东西


另一个解决方法是不重载,但允许具有大量可选参数的函数,如:

function createDelegate<Ctx extends Object, R, A=never, B=never, C=never, D=never>(fn: (a?: A, b?: B, c?: C, d?: D) => R, context: Ctx): (this: Ctx, a?: A, b?: B, c?: C, d?: D) => R {
  return fn.bind(context);
}
无论如何,这是我能做的最好的了。希望有帮助;祝你好运

methodWithDelegate(createDelegate(function(val1, val2) {
  // handle the possible undefined issue 
  if (typeof val1 === 'undefined') throw new Error("No");
  // now the following line works for you
  val1.substring(2);
}, "CONTEXT"));