【问题标题】:Using Parameters<Fn> where Fn extends a function Type使用 Parameters<Fn> 其中 Fn 扩展函数类型
【发布时间】:2021-08-26 10:13:05
【问题描述】:

这与我在使用 Redux Saga 生成器时遇到的问题有关。他们对call 的定义之一是(不包括实现):

// this is taken from redux saga and cannot be changed
function call<Fn extends (...args: any[]) => any>(
  fn: Fn,
  ...args: Parameters<Fn>
): CallEffect<SagaReturnType<Fn>> { ... }

我试图这样称呼它:

function test<F extends (a: string, b: number) => any>(f: F) {
  return call(f, 'a', 0)
}

此时我得到错误:'["a", 0]' 类型的参数不可分配给'Parameters' 类型的参数。

但如果F 扩展(a: string, b: number) =&gt; any,那不应该是可赋值的吗?

【问题讨论】:

  • 如果我没看错,所有参数都必须是相同的类型才能赋值。只有可以相互分配的类型,例如,如果参数都是特定接口的,它可以工作。解决此问题的方法是在运行时手动检查每个参数的类型。
  • 如果您不能更改calltest 的调用签名,那么您将需要类型断言或扩展,因为编译器无法进行高阶分析以当F 是未解析的泛型类型时,确定(...a: Parameters&lt;F&gt;)=&gt;ReturnType&lt;F&gt;) 可以替代FHere 是我看到的选项;这些对你有用吗?如果是这样,我很乐意写一个答案。
  • 我无法更改call 签名,它来自redux saga,但我可以更改test。真正的call 函数返回一个值并从Fn 推断返回类型。扩大或断言会导致真正的返回类型丢失并被any 替换。所以我想我只剩下test&lt;R&gt;(f: (a: string, b: number) =&gt; R)
  • @fredrik 如果类型不同,参数将返回一个元组。即:type F = (a: string, b: number) =&gt; booleantype P = Parameters&lt;F&gt; 给出type P = [a: string, b: number]

标签: typescript typescript-generics


【解决方案1】:

Prameters 等条件类型通常不能很好地处理未解析的泛型类型。由于类型不确定,因此打字稿通常不会评估条件类型。

您可以使用与call 略有不同的签名来解决它:

function call<A extends any[], R>(
  fn: (...a: A) => R,
  ...args: A
): void {}

function test<F extends (a: string, b: number) => any>(f: F): void {
  call(f, 'a', 0)
}

Playground Link

【讨论】:

  • 不幸的是,调用的签名直接取自redux saga,所以我无法真正更改它。
【解决方案2】:

F 是一个未解析的泛型时,引擎还不够聪明,无法知道 ['a', 0] 可以分配给Parameters&lt;F&gt;

我们可以通过首先将f 分配给我们关心的具体类型的变量来解决这个问题:

function test<F extends (x: string, y: number) => any>(f: F) {
  const f2: (x: string, y: number) => any = f;
  return call(f2, 'a', 0)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-27
    • 2020-11-04
    • 2014-05-19
    • 2011-01-19
    • 2021-01-26
    • 2021-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多