我试图弄清楚如何包装已定义的函数,以便在保留其签名的同时做更多工作。这是理想的效果:
程序员定义接口:
const actions = {
first: (id: number) => {/*...*/},
second: (name: string) => {/*...*/}
}
let actionsInterface = wrap(actions)
export actionsInterface
actionsInterface
应该(即目标)具有以下界面:
{
first: (id: number) => void,
second: (name: string) => void
}
它基本上提供了与最初定义的完全相同的接口(即,具有相同功能的列表,具有相同的参数,不计算返回类型),但是正在做的其他工作由{{ 1}}。
我当前的实现类似于:
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
答案 0 :(得分:2)
您的通用类型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)