我正在尝试创建一个通用的包装函数,它将包装传递给它的任何函数.
在最基本的包装函数看起来像
function wrap<T extends Function>(fn: T) {
return (...args) => {
return fn(...args)
};
}
Run Code Online (Sandbox Code Playgroud)
我想尝试使用它:
function foo(a: string, b: number): [string, number] {
return [a, b];
}
const wrappedFoo = wrap(foo);
Run Code Online (Sandbox Code Playgroud)
现在wrappedFoo正在获得一种类型(...args: any[]) => any
是否有可能wrappedFoo模仿其包装功能的类型?
for*_*010 14
这适用于任意数量的参数,并保留所有参数和返回类型
const wrap = <T extends Array<any>, U>(fn: (...args: T) => U) => {
return (...args: T): U => fn(...args)
}
Run Code Online (Sandbox Code Playgroud)
tik*_*zky 13
可以创建一个包装函数,通过进行2次更改来接受并返回与包装函数相同的类型
T泛型 <any>例如:
function wrap<T extends Function>(fn: T): T {
return <any>function(...args) {
return fn(...args)
};
}
Run Code Online (Sandbox Code Playgroud)
那么类型 const wrappedFoo = wrap(foo);
然后将正确地:
(a: string, b: number) => [string, number].
Run Code Online (Sandbox Code Playgroud)
最近需要使用箭头函数来做到这一点,想出了一种比其他一些答案更容易工作的方法,并解决了扩展运算符的问题和Symbol.iterator(在 ts 3.8 中测试)
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;
};
Run Code Online (Sandbox Code Playgroud)
AnyFunction 需要这样我们就可以使用 rest 运算符并提取参数类型/返回类型
Func extends AnyFuncthen 让我们描述我们特别喜欢的任何函数的类型Func围绕包装函数无法用不同的子类型实例化的问题,因此我们需要重新构造它
Parameters<Func> 获取任意参数作为元组
Symbol.iterator问题的具体解决方法是使用...Array.from(args)而不是...argsReturnType<Func> 获取任意返回类型包装函数现在将具有与内部函数相同的签名,几乎可以执行任何操作
const foo = (a: string, b: number): number => a.length + b;
const wrappedFoo = wrap<typeof foo>(foo);
foo('hello', -5); // => 0
wrappedFoo('hello', -5); // => 0
Run Code Online (Sandbox Code Playgroud)
这是可能的,但如果您希望能够传递不同类型和数量的参数,可能会有点混乱。
你的例子可以这样完成:
function wrap<A, B, C>(fn: (a: A, b: B) => C) {
return (a: A, b: B): C => {
return fn(a, b);
};
}
Run Code Online (Sandbox Code Playgroud)
那么类型为:
const wrappedFoo = wrap(foo);
Run Code Online (Sandbox Code Playgroud)
是(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);
Run Code Online (Sandbox Code Playgroud)
(操场上的代码)
我认为这会更容易使用。
| 归档时间: |
|
| 查看次数: |
4029 次 |
| 最近记录: |