Typescript 是否可以包装函数并保留其类型?
我正在尝试创建一个通用包装函数,它将包装传递给它的任何函数 在最基本的情况下,包装器函数看起来像Typescript 是否可以包装函数并保留其类型?,typescript,Typescript,我正在尝试创建一个通用包装函数,它将包装传递给它的任何函数 在最基本的情况下,包装器函数看起来像 function wrap<T extends Function>(fn: T) { return (...args) => { return fn(...args) }; } 现在wrappedFoo正在获取一种类型的(…args:any[])=>any 是否可以让wrappedFoo模拟其包装的函数类型?这是可能的,但如果希望能够传递不同类型和
function wrap<T extends Function>(fn: T) {
return (...args) => {
return fn(...args)
};
}
现在wrappedFoo
正在获取一种类型的(…args:any[])=>any
是否可以让
wrappedFoo
模拟其包装的函数类型?这是可能的,但如果希望能够传递不同类型和数量的参数,可能会有点混乱
您的示例可以这样做:
function wrap<A, B, C>(fn: (a: A, b: B) => C) {
return (a: A, b: B): C => {
return fn(a, b);
};
}
Is(a:string,b:number)=>[string,number]
() 但是,正如您所看到的,如果您希望能够使用不同的签名,那么使用它就不是很舒服(例如,我的示例仅适用于两个参数) 您可以只传递一个由接口支持的参数:
function wrap<In, Out>(fn: (params: In) => Out) {
return (params: In): Out => {
return fn(params);
};
}
interface FooParams {
a: string;
b: number;
}
function foo(params: FooParams): [string, number] {
return [params.a, params.b];
}
const wrappedFoo = wrap(foo);
函数换行(fn:(参数:In)=>Out){
返回(参数:输入):输出=>{
返回fn(参数);
};
}
接口参数{
a:弦;
b:数字;
}
函数foo(params:FooParams):[字符串,数字]{
返回[参数a,参数b];
}
const wrappedFoo=wrap(foo);
()
在我看来,这将更容易使用。可以创建一个包装函数,它接受并返回与其包装的函数相同的类型,只需做2个更改
T
泛型
function wrap<T extends Function>(fn: T): T {
return <any>function(...args) {
return fn(...args)
};
}
可以使用为包含0、1、2、3、4或更多参数的包装函数提供特定类型。如果您的一个函数需要更多的参数,请添加一个额外的重载,或者让它回退到rest参数的情况
function wrap<TResult>(fn: () => TResult) : () => TResult;
function wrap<T1, TResult>(fn: (param1 : T1) => TResult) : (param1 : T1) => TResult;
function wrap<T1, T2, TResult>(fn: (param1 : T1, param2 : T2) => TResult) : (param1 : T1, param2 : T2) => TResult;
function wrap<T1, T2, T3, TResult>(fn: (param1 : T1, param2 : T2, param3 : T3) => TResult) : (param1 : T1, param2 : T2, param3 : T3) => TResult;
function wrap<T1, T2, T3, T4, TResult>(fn: (param1 : T1, param2 : T2, param3 : T3, param4 : T4) => TResult) : (param1 : T1, param2 : T2, param3 : T3, param4 : T4) => TResult;
function wrap<TParam, TResult>(fn: (...params : TParam[]) => TResult) : (...params : TParam[]) => TResult {
return (...params) => {
return fn(...params);
};
}
函数包装(fn:()=>TResult):()=>TResult;
函数换行(fn:(param1:T1)=>TResult:(param1:T1)=>TResult;
函数换行(fn:(param1:T1,param2:T2)=>TResult:(param1:T1,param2:T2)=>TResult;
函数换行(fn:(param1:T1,param2:T2,param3:T3)=>TResult:(param1:T1,param2:T2,param3:T3)=>TResult;
函数换行(fn:(param1:T1,param2:T2,param3:T3,param4:T4)=>TResult:(param1:T1,param2:T2,param3:T3,param4:T4)=>TResult;
函数换行(fn:(…参数:TParam[])=>TResult:(…参数:TParam[])=>TResult{
返回(…参数)=>{
返回fn(…参数);
};
}
它不是很漂亮,但它提供了最准确的类型。这适用于任意数量的参数,并保留所有参数和返回类型
const wrap = <T extends Array<any>, U>(fn: (...args: T) => U) => {
return (...args: T): U => fn(...args)
}
const wrap=(fn:(…args:T)=>U)=>{
返回(…args:T):U=>fn(…args)
}
最近需要使用箭头函数来实现这一点,提出了一种比其他答案更容易实现的方法,并解决了扩展运算符和符号的问题。迭代器
(在ts 3.8中测试)
谢谢你的回答,我不想强迫每个被包装的函数接受一个params对象。。。我一直在胡思乱想,我想我已经找到了解决这个特殊问题的方法…
…args
在Typescript中生成了一个for循环
,您可以通过使用函数局部变量arguments
来避免这个问题。太棒了!对于返回与被包装函数相同的值但不直接返回函数调用的包装器,是否也可能出现类似的情况?这确实令人惊讶。一个小问题是,对any的强制转换确实破坏了返回值的类型测试,这意味着如果您的包装器错误地没有返回与包装函数typescript相同的类型,则无法捕获该类型。我正在寻找一个类似的实现,但其中fn
是可选的,并且默认值为()=>{}
。这可能吗?我测试了这个,它可以工作,但我不知道为什么。这里有T
的名字吗?我希望
是指“T型同质元素的数组”,或者,如果参数是[string,number]
则是数组
。Array
怎么能表示“按特定顺序排列的特定系列类型的数组”?我认为不需要t
<代码>应足以满足此要求signature@ElliotNelson@jcalz是的,可以使用Array
代替,我用T绕过我的eslint警告,但是Array
更清晰,谢谢你的反馈!内部函数上的显式返回类型,:U
让我有点困惑。我认为它可以从参数类型推断出来?在VSCode中工作得很好!甚至参数的签名/名称也被保留
(a: string, b: number) => [string, number].
function wrap<TResult>(fn: () => TResult) : () => TResult;
function wrap<T1, TResult>(fn: (param1 : T1) => TResult) : (param1 : T1) => TResult;
function wrap<T1, T2, TResult>(fn: (param1 : T1, param2 : T2) => TResult) : (param1 : T1, param2 : T2) => TResult;
function wrap<T1, T2, T3, TResult>(fn: (param1 : T1, param2 : T2, param3 : T3) => TResult) : (param1 : T1, param2 : T2, param3 : T3) => TResult;
function wrap<T1, T2, T3, T4, TResult>(fn: (param1 : T1, param2 : T2, param3 : T3, param4 : T4) => TResult) : (param1 : T1, param2 : T2, param3 : T3, param4 : T4) => TResult;
function wrap<TParam, TResult>(fn: (...params : TParam[]) => TResult) : (...params : TParam[]) => TResult {
return (...params) => {
return fn(...params);
};
}
const wrap = <T extends Array<any>, U>(fn: (...args: T) => U) => {
return (...args: T): U => fn(...args)
}
type AnyFunction = (...args: any[]) => any;
const wrap = <Func extends AnyFunction>(
fn: Func,
): ((...args: Parameters<Func>) => ReturnType<Func>) => {
const wrappedFn = (...args: Parameters<Func>): ReturnType<Func> => {
// your code here
return fn(...args);
};
return wrappedFn;
};
const foo = (a: string, b: number): number => a.length + b;
const wrappedFoo = wrap<typeof foo>(foo);
foo('hello', -5); // => 0
wrappedFoo('hello', -5); // => 0