在以下我的问题的简化示例中:
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
?
这有效:
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
}