带有可选剩余参数的嵌套 TypeScript 函数:“T”可以用不同的子类型实例化

问题描述 投票:0回答:1

在以下我的问题的简化示例中:

const factory = <T extends unknown[]>(
  fn: (...args: T) => void
) => {
  const transformedFn = (...args: T) => {
    console.log('called with', ...args)
    return fn(...args)
  }

  // init
  transformedFn() // TypeScript error here

  return transformedFn
}

// usage:
const fn = (x?: number) => {
  return x || -1
}
factory(fn)()

我收到 TypeScript 错误:

“[]”类型的参数不可分配给“T”类型的参数。 '[]' 可分配给类型 'T' 的约束,但 'T' 可以使用约束 'unknown[]' 的不同子类型进行实例化。

游乐场

令人困惑的是,这有效:

const fn = <T extends unknown[]>(...args: T) => {
  return args
}
fn()

如何让 TypeScript 相信在这两种情况下它是相同的

T

typescript
1个回答
0
投票

这有效:

const factory = <T extends unknown>(
  fn: (...args: T[]) => void
) => {
  const transformedFn = (...args: T[]) => {
    console.log('called with', ...args)
    return fn(...args)
  }

  // init
  transformedFn()

  return transformedFn
}

T extends unknown
纯粹是为了防止 TypeScript Playground 尝试将其解析为 React 代码。

您原来的方法不起作用的原因是因为您可以传入扩展

unknown[]
的类型,但不允许使用空数组,如下所示:

function example<T extends unknown[]>(...args: T) {
}

const args = [1, 2, 3] as const;

example(args);

这会导致在

transformedFn
函数体中不带参数地调用
factory
不正确,因为存在一个满足
T extends unknown[]
且不满足
[]
的类型(这是你得到的类型)当不带参数调用
transformedFn
时)。

接下来,您还可以保留现有代码,但也可以传入

transformedFn
调用的参数 - 这也可以工作并保留您的原始类型:

const factory = <T extends unknown[]>(
  fn: (...args: T) => void,
  args: T
) => {
  const transformedFn = (...args: T) => {
    console.log('called with', ...args)
    return fn(...args)
  }

  // init
  transformedFn(...args)

  return transformedFn
}
© www.soinside.com 2019 - 2024. All rights reserved.