2016-07-26 4 views
2

Ich versuche, eine generische Wrapper-Funktion zu erstellen, die alle an sie übergebenen Funktionen umschließt.Ist es möglich, eine Funktion zu umbrechen und ihre Typen beizubehalten?

Am sehr einfach die Wrapper-Funktion so etwas wie

function wrap<T extends Function>(fn: T) { 
    return (...args) => { 
     return fn(...args) 
    }; 
} 

aussehen würde ich versuche, es zu benutzen mag:

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

const wrappedFoo = wrap(foo); 

Gerade jetzt wrappedFoo wird immer eine Art (...args: any[]) => any

Ist es möglich, wrappedFoo zu erhalten, um die Typen der Funktion nachzuahmen?

Antwort

1

Es ist möglich, aber könnte ein bisschen unordentlich werden, wenn Sie in der Lage sein möchten, verschiedene Arten und eine Anzahl von Argumenten zu übergeben.

function wrap<A, B, C>(fn: (a: A, b: B) => C) { 
    return (a: A, b: B): C => { 
     return fn(a, b); 
    }; 
} 

Dann ist die Art von:

const wrappedFoo = wrap(foo); 

Ist (a: string, b: number) => [string, number]

Ihr Beispiel kann wie folgt durchgeführt werden.
(code in playground)

Aber wie Sie sehen können, ist dies nicht sehr komfortabel mit, falls Sie arbeiten verschiedene Signaturen, die Sie (zum Beispiel mein Beispiel funktioniert nur für zwei params) zu verwenden, um der Lage sein möchten.

Was Sie tun können, ist nur ein param passieren, die durch eine Schnittstelle unterstützt wird:

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); 

(code in playground)

Das wird viel einfacher sein, mit meiner Meinung nach zu arbeiten.

+0

Danke für die Antwort, ich würde lieber nicht jede Funktion gezwungen, um in einem einzigen params Objekt zu nehmen ... Ich habe weiter rumgespielt und denke, ich habe eine Lösung für dieses spezielle Problem ... – tikotzky

5

Es ist möglich, eine Wrapper-Funktion zu erstellen, die die gleichen Typen wie die Funktion von ihrer Verpackung akzeptiert und kehrt zu machen 2

  1. den Rückgabewert der Wrapper-Funktion der T generisch sein, dass Sie Verpackung angeben ändert
  2. werfen die Funktion, die Sie <any> zurückkehr

zum Beispiel:

function wrap<T extends Function>(fn: T): T { 
    return <any>function(...args) { 
     return fn(...args) 
    }; 
} 

Dann ist die Art von const wrappedFoo = wrap(foo);

wird dann richtig:

(a: string, b: number) => [string, number]. 
+0

' ... args' erzeugt in Typoskript eine 'for-Schleife', die Sie vermeiden können, indem Sie einfach die Funktion local variable' arguments' verwenden. – TheVTM

+0

Das ist großartig! Ist etwas Ähnliches für Wrapper möglich, die den gleichen Wert wie die Wrapped-Funktion zurückgeben, aber den Funktionsaufruf nicht direkt zurückgeben? – Macks

0

Sie overloads verwenden können bestimmte Arten zum Einwickeln von Funktionen mit 0, 1, 2, 3, 4 oder mehr Parametern zur Verfügung zu stellen. Falls eine Ihrer Funktionen noch mehr Parameter benötigt, fügen Sie eine zusätzliche Überladung hinzu oder lassen Sie sie einfach auf den Fall der restlichen Argumente zurückfallen.

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); 
    }; 
} 

Es ist nicht sehr hübsch, aber es gibt den genauesten Typ.

Verwandte Themen