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

时间:2017-09-16 11:13:42

标签: typescript generics

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

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

我尝试了几种方法,都失败了。

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

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

有解释吗?

有解决方案吗?

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"));

1 个答案:

答案 0 :(得分:1)

关于为什么会这样,我没有一个很好的答案。您可能希望在Microsoft/TypeScript上提出问题并要求解释。毫无疑问,泛型类型参数推断,函数参数推断和重载决策之间存在一些相互作用。

显然,一种解决方法就是将{ path: 'module2', loadChildren: './modules/module2/module2.module#Module2Module', canActivate: [Guard] } 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); } ,函数参数也将是string。所以你需要在函数中处理string | undefined,这就是为什么这是一个解决方法而不是解决方案:

undefined

无论如何,这是我能做的最好的事情。希望能帮助到你;祝你好运!