generics - 如何在Typescript中参数化函数参数元组

标签 generics functional-programming typescript

使用 Typescript 1.4,假设我有一个带有签名的高阶函数:

interface F<A,B> {
    (a: (...x:any[]) => A): (...x:any[]) => B
}

函数“F”采用具有一组参数“x”的函数“a”。函数“F”返回一个新函数,它与函数“a”具有完全相同的参数集。

我一直在尝试找到一种在 Typescript 中表达这一点的方法,但我做得不够。例如:
interface F<X extends Array<any>,A,B> {
    (a: (...x:X) => A): (...x:X) => B
}

编译器只是提示:error TS2370: A rest parameter must be of an array type.
尽管无论如何都感觉不对,即使它确实编译了。我想我真的需要这样的东西:
interface F<X extends Tuple,A,B> {
    (a: (...x:X) => A): (...x:X) => B
}

任何人都知道目前 Typescript 是否可以实现这种事情(撰写本文时为 1.4)?或任何建议?

示例:

(注意:这不是我的实际用例,我只是在这里使用日志作为一个简单的例子 - 请不要关注这方面)
// a higher-order function that takes any function and
// returns a new function which takes the same args
// passing them to the original fn and logging the args along with the result

function f(a:(...x:any[]) => any): (...x:any[]) => void {
    return (...x:any[]) => {
        console.log('('+x.join(',')+') => ', a.apply(undefined, x));
    }
}

function a(j:string, k:number): boolean {
    return j === String(k);
}

var b = f(a);

b("1", 1);
b("a", 2);

控制台输出:
(1,1) =>  true
(a,2) =>  false

所以这是可行的,但派生函数“b”具有以下隐含签名:
(...x:any[]) => void

理想情况下,我希望它与函数“a”具有相同的参数,即:
(j: string, k: number) => void

我知道我可以明确地定义它,但是它非常冗长而且一点也不理想,这有点违背了首先拥有强类型的意义:
var b: (j:string, k:number) => void = f(a);

最佳答案

要将一个函数与另一个具有不同返回类型的函数包装在一起,可以使用重载一个技巧:

function wrap<R>(fn0: ()=> any, p:(f,a)=>R): () => R;
function wrap<R,T>(fn1: (t:T)=> any, p:(f,a)=>R): (t:T) => R;
function wrap<R, T, U>(fn2: (t:T, u:U)=> any, p:(f,a)=>R): (t:T,u:U) => R;
function wrap<R, T, U, V>(fn3: (t:T, u:U, v:V)=> any, p:(f,a)=>R): (t:T,u:U, v:V) => R;
function wrap<R, T, U, V, X>(fn4: (t:T, u:U, v:V, x:X)=> any, p:(f,a)=>R): (t:T,u:U, v:V, x:X) => R;
// ...
function wrap<R>(fn: Function, proc:Function):Function {
	return (...args) => proc(fn, args);
}

// wrap is called with two functions fn and proc
// result is a function with argument types from fn and return type of proc 

function serialize(fn, args):string {
  return JSON.stringify(fn(...args))
}

function foo(a:number,b:string) {
  return true;
}

var wrapped = wrap(foo,serialize)
// type is (a:number,b:string) => string


请注意,它仅适用于参数数量有限的函数。

关于generics - 如何在Typescript中参数化函数参数元组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28953366/

相关文章:

haskell - IO 相关任务中的函数式方式

function - Scala -- 如何在非函数类型上使用仿函数?

javascript - (): meaning in javascript function

javascript - Typescript - 将 ngModel 绑定(bind)到对象的属性

generics - 相互定义的参数中的 F# 通用单位

java - 使用泛型和 lambda 重载方法时调用方法不明确

java - 泛型类的 XStream 反序列化返回 java.lang.Object

c# - 基于key的KeyValueComparer

javascript - 编写可重用的 javascript 模块和库。

javascript - ionic 关闭模式并返回上一页发送数据