是否可以包装一个函数,使包装器具有相同的参数以及位于这些参数之后的另一个参数?
Is it possible to wrap a function so that the wrapper has the same arguments plus another argument which is situated after these arguments?
我的目标是包装一个 API 函数,使包装器具有与 API 函数相同的参数,然后还有一个额外的最终参数。 API 函数非常通用,因此包装器需要从这个内部函数中获取类型和参数。
我的理由是我需要使用额外的可选参数来增强 API 函数。对于使用此包装函数的其他开发人员来说,将此可选参数作为第一个参数将是一种糟糕的体验。
我目前的尝试如下:
const insideFunc = (a: string): string => {
return a
}
const wrapperFunc = <F extends (...args: any[]) => any>(
fn: F
): ((b?: string, ...args: Parameters<F>) => [ReturnType<F>, string]) => {
return (b?: string, ...args: Parameters<F>):[ReturnType<F>, string] => {
return [fn(...args), b]
}
}
这几乎是我所需要的,但问题是参数 b
必须 在 内部函数的参数之前。
在平行宇宙中,解决方案将在新参数之前有其余参数,如下所示:
const insideFunc = (a: string): string => {
return a
}
const wrapperFunc = <F extends (...args: any[]) => any>(
fn: F
): ((...args: Parameters<F>, b?: string) => [ReturnType<F>, string]) => {
return (...args: Parameters<F>, b?: string):[ReturnType<F>, string] => { //Observe the difference in argument order.
return [fn(...args), b]
}
}
但是,由于其余参数必须是最后一个参数,因此会出错。
是否有另一种方法可以解决这个问题,使内部函数参数可以在列表中排在第一位?
在函数的参数列表中,扩展 必须 出现在其他参数之后。但是,对于元组类型,不是。
这意味着您可以像这样声明 args
:
(...args: [...args: Parameters<F>, b: string])
请注意,此元组的每个成员都已命名,这有助于保留有关原始参数名称的智能提示。
这确实意味着您必须自己解析 args
,但这并不难:
const originalArgs = args.slice(0, -1)
const b = args[args.length - 1]
return [fn(...originalArgs), b]
像这样使用时似乎有效:
const insideFunc = (name: string, age: number, likes: string[]): string => {
return `${name} is ${age} and likes ${likes.join(', ')}`
}
const fn = wrapperFunc(insideFunc)
console.log(fn(
'Alex',
39,
['cool stuff', 'awesome things'],
'and also snowboarding'
))
//-> ["Alex is 39 and likes cool stuff, awesome things", "and also snowboarding"]
当您将鼠标悬停在 fn
此处时,您可以看到参数名称保留在报告类型中:
const fn: (
name: string,
age: number,
likes: string[],
b: string
) => [string, string]
One issue with this solution is that if b is an optional argument and not provided.
好吧,您可以向内部函数询问其 length
,其中 returns 它接受的参数数量。
const originalArgs = args.slice(0, fn.length)
const b = args[fn.length + 1]
但是,如果内部函数有可选参数,或者像 ...args
这样展开,这显然会使事情复杂化。事实上,我认为这会让你无法知道哪些参数适用于你的内部函数,哪些应该在后面。
我可以推荐一个替代方案吗API?类似于:
fn([original, args, here], extraArg)
这样一来,就可以很容易地分辨出函数有什么用,什么是额外的。我认为再多的聪明元组类型或数组切片也无法为您提供完美的、适用于所有情况的解决方案,而无需明确地将原始参数与额外参数分开。
或者作为嵌套函数,仅在提供额外参数时才调用内部函数?
fn(original, args, here)(extraArg)
我的目标是包装一个 API 函数,使包装器具有与 API 函数相同的参数,然后还有一个额外的最终参数。 API 函数非常通用,因此包装器需要从这个内部函数中获取类型和参数。
我的理由是我需要使用额外的可选参数来增强 API 函数。对于使用此包装函数的其他开发人员来说,将此可选参数作为第一个参数将是一种糟糕的体验。
我目前的尝试如下:
const insideFunc = (a: string): string => {
return a
}
const wrapperFunc = <F extends (...args: any[]) => any>(
fn: F
): ((b?: string, ...args: Parameters<F>) => [ReturnType<F>, string]) => {
return (b?: string, ...args: Parameters<F>):[ReturnType<F>, string] => {
return [fn(...args), b]
}
}
这几乎是我所需要的,但问题是参数 b
必须 在 内部函数的参数之前。
在平行宇宙中,解决方案将在新参数之前有其余参数,如下所示:
const insideFunc = (a: string): string => {
return a
}
const wrapperFunc = <F extends (...args: any[]) => any>(
fn: F
): ((...args: Parameters<F>, b?: string) => [ReturnType<F>, string]) => {
return (...args: Parameters<F>, b?: string):[ReturnType<F>, string] => { //Observe the difference in argument order.
return [fn(...args), b]
}
}
但是,由于其余参数必须是最后一个参数,因此会出错。
是否有另一种方法可以解决这个问题,使内部函数参数可以在列表中排在第一位?
在函数的参数列表中,扩展 必须 出现在其他参数之后。但是,对于元组类型,不是。
这意味着您可以像这样声明 args
:
(...args: [...args: Parameters<F>, b: string])
请注意,此元组的每个成员都已命名,这有助于保留有关原始参数名称的智能提示。
这确实意味着您必须自己解析 args
,但这并不难:
const originalArgs = args.slice(0, -1)
const b = args[args.length - 1]
return [fn(...originalArgs), b]
像这样使用时似乎有效:
const insideFunc = (name: string, age: number, likes: string[]): string => {
return `${name} is ${age} and likes ${likes.join(', ')}`
}
const fn = wrapperFunc(insideFunc)
console.log(fn(
'Alex',
39,
['cool stuff', 'awesome things'],
'and also snowboarding'
))
//-> ["Alex is 39 and likes cool stuff, awesome things", "and also snowboarding"]
当您将鼠标悬停在 fn
此处时,您可以看到参数名称保留在报告类型中:
const fn: (
name: string,
age: number,
likes: string[],
b: string
) => [string, string]
One issue with this solution is that if b is an optional argument and not provided.
好吧,您可以向内部函数询问其 length
,其中 returns 它接受的参数数量。
const originalArgs = args.slice(0, fn.length)
const b = args[fn.length + 1]
但是,如果内部函数有可选参数,或者像 ...args
这样展开,这显然会使事情复杂化。事实上,我认为这会让你无法知道哪些参数适用于你的内部函数,哪些应该在后面。
我可以推荐一个替代方案吗API?类似于:
fn([original, args, here], extraArg)
这样一来,就可以很容易地分辨出函数有什么用,什么是额外的。我认为再多的聪明元组类型或数组切片也无法为您提供完美的、适用于所有情况的解决方案,而无需明确地将原始参数与额外参数分开。
或者作为嵌套函数,仅在提供额外参数时才调用内部函数?
fn(original, args, here)(extraArg)