我正在尝试找出如何包装定义的函数,以便我可以在保留其签名的同时做额外的工作。这是想要的效果:
程序员定义接口:
const actions = {
first: (id: number) => {/*...*/},
second: (name: string) => {/*...*/}
}
let actionsInterface = wrap(actions)
export actionsInterface
actionsInterface
应该(即这就是目标)具有以下界面:
{
first: (id: number) => void,
second: (name: string) => void
}
它基本上提供了与最初定义相同的接口(即相同的函数列表,具有相同的参数,不包括返回类型),但是还有一些额外的工作正在完成,这些工作是由
wrap()
注入的。
我当前的实现是这样的:
type VarFn = (...args: any) => any
function wrap<T, K extends keyof T>
(funcList: Record<K, T[K] extends VarFn ? T[K] : never>) {
// this maps a specific function to a function that does something extra
function wrapOne<T extends (...args: any)=>any>(fn: T) {
return (...args: Parameters<typeof fn>) => {
someMagicThingyExtra(fn(args))
}
}
// we iterate through the list and map each function to the one that's doing something extra
type FuncMap = Record<K, (...args: Parameters<T[K] extends VarFn ? T[K] : never>)=>void>
let map: FuncMap
for (var Key in funcList) {
let func = funcList[Key]
map[Key] = wrapOne(func)
}
return map
}
但是,我在
wrap(actions)
上收到以下错误:
Argument of type '{ first: (id: number) => void; second: (name: string) => void; }' is not assignable to parameter of type 'Record<"first" | "second", never>'.
Types of property 'first' are incompatible.
Type '(id: number) => void' is not assignable to type 'never'.
因此,由于某种原因,它与
(id: number) => void
不匹配,因此推断出 (...args: any) => any
。所以我尝试了一些不同的事情:
never
没有错误,但是我的
function wrap2<T, K extends keyof T, U extends VarFn>
(funcList: Record<K, U>) {
function wrapOne<T extends (...args: any)=>any>(fn: T) {
return (...args: Parameters<typeof fn>) => {
someMagicThingyExtra(fn(args))
}
}
type FuncMap = Record<K, (...args: Parameters<U>)=>void>
let map: FuncMap
for (var Key in funcList) {
let func = funcList[Key]
map[Key] = wrapOne(func)
}
return map
}
的返回类型是:
wrap2(actions)
...并且我丢失了参数类型,这违背了尝试包装功能但保留签名(即参数类型)的整个目的。
欢迎任何帮助或指导。谢谢!
编辑:
Dragomir 提供的答案完全保留了签名(参数类型和返回类型)。我的用例还需要将返回类型更改为
{
first: (...args: any) => void
second: (...args: any) => void
}
,这就是我实现它的方法:
void
function wrap<T extends Record<keyof T, (...args: any)=>any>>(funcList: T) {
// this maps a specific function to a function that does something extra
function wrapOne<T extends (...args: any) => any>(fn: T) {
return ((...args: Parameters<typeof fn>): void => {
someMagicThingyExtra(fn(args))
})
}
// we iterate through the list and map each function to the one that's doing something extra
type WrapMap = {
[K in keyof T]: (...args: Parameters<T[K]>)=>void
}
let map: WrapMap
for (var Key in map) {
map[Key] = wrapOne(funcList[Key])
}
return map
}
应该有一个约束,即它的所有成员都是
T
类型,您可以轻松地使用 VarFn
来实现。由于返回的类型与输入类型 T extends Record<keyof T, VarFn>
完全相同,因此可以是 map
类型。T
游乐场链接
type VarFn = (...args: any) => any
function wrap<T extends Record<keyof T, VarFn>>(funcList: T) {
// this maps a specific function to a function that does something extra
function wrapOne<T extends (...args: any) => any>(fn: T): T {
return ((...args: Parameters<typeof fn>) => {
return someMagicThingyExtra(fn(args))
}) as T
}
// we iterate through the list and map each function to the one that's doing something extra
let map = {} as T
for (var Key in funcList) {
let func = funcList[Key]
map[Key] = wrapOne(func)
}
return map
}
const actions = {
first: (id: number) => {/*...*/ },
second: (name: string) => {/*...*/ }
}
let actionsInterface = wrap(actions)
const newFunction = ((one, two) => {
const result = oldFunction(one, two)
// ...
return result
}) as typeof oldFunction