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

时间:2015-03-09 23:05:13

标签: generics functional-programming typescript

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

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

功能&#39; F&#39;采取功能&#39; a&#39;它有一组参数&#39; x&#39;。功能&#39; F&#39;返回一个新函数,它与函数&#39; a&#39;。

具有完全相同的args集

我一直试图找到一种在打字稿中表达这种方式的方法,但我很快就会出现。例如:

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

所以这是有效的,但派生的功能&#39; b&#39;有隐含的签名:

(...x:any[]) => void

理想情况下,我希望它具有与功能相同的参数&#39; a&#39;即:

(j: string, k: number) => void

我知道我可以明确地定义它,但它非常冗长而且根本不是理想的,它首先打破了强打字的重点:

var b: (j:string, k:number) => void = f(a);

3 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:0)

  

函数'F'取函数'a',它有一组参数'x'。函数'F'返回一个新函数,它与函数'a'具有完全相同的args集。

规范有点不清楚,但根据我对你的意思的理解,这是一个样本

// Function 'F' takes function 'a' which has a set of parameters 'x'
// and returns a new function which has exactly the same set of args as function 'a'
function F<A extends Function>(a:A):A{
    return a;
}

var foo = F(function(a:number,b:number):void{});

foo (1,3); // okay 
foo(1); // ERROR

<强>更新

您的用例示例:

function f<A extends Function>(a:A):A {
    var newFunc = (...x:any[]) => {
        console.log('('+x.join(',')+') => ', a.apply(undefined, x));
        return null;
    }
    return <any>newFunc;
}

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

var b = f(a);

b("1", 1);
b("a", 2);
b('123','123'); // ERROR

注意:我们捕获了参数的返回类型。我没有看到一种方法来捕获只是参数

答案 2 :(得分:0)

目前无法在TypeScript类型系统中表达这一点。这是一个长期存在的问题,您可以在https://github.com/Microsoft/TypeScript/issues/212https://github.com/Microsoft/TypeScript/issues/5453

上查看