2017-02-21 13 views
1

ich eine Funktion höherer Ordnung, müssen sie beispielsweise in Vanille JS wie folgt aus:Wie man richtig eine Funktion höherer Ordnung

function log(fn) { 
    return (...args) => { 
    console.log("Calling", fn.name); 
    return fn(...args); 
    } 
} 

und verwendet wie folgt aus:

let name; 
const setName = log((newName) => { 
    name = newName; 
}); 
setName("Hello"); // output "Calling setName" 

Wie kann ich richtig eingeben dies in TS so, dass setName hat die richtige Funktion Signatur? Bedeutung:

setName("hello") // OK 
setName() // Error, missing arg 
setName(123) // Error, number not string 

Was ich mit so weit kommen habe, ist:

function log<F extends Function>(fn: F): F { 
    return (...args: any[]) => { 
    console.log("Calling", fn.name); 
    return fn(...args); 
    } 
} 

let name; 
const setName = log((newName: string) => { 
    name = newName; 
}); 

, die die Art und Weise funktioniert Ich will (I Argument Typen auf setName Kontrolle zu bekommen), aber ich erhalte einen Compiler-Fehler auf der log Funktion Rückkehr:

Error: TS2322:Type '(...args: any[]) => any' is not assignable to type 'F'.

Auch wenn ich <F extends (...args: any[]) => any> verwenden erhalte ich den gleichen Fehler. Grundsätzlich weiß ich nicht, wie die zurückgegebene Funktion den generischen Typ F erfüllt.

Wie kann ich das tun?

Antwort

2

Mit einer Funktion Überladungs ​​

Function overloads verwendet werden kann. Es ist ein Weg, um die Definition von der Implementierung zu trennen:

function log<F extends Function>(fn: F): F 
function log(fn: Function) { 
    return (...args) => { 
     console.log("Calling", fn.name); 
     return fn(...args); 
    } 
} 

ich die Überlastung Version mag, weil es Typoskript Definitionen erzeugen hilft, wenn das Modul als vorkompilierte NPM-Paket verteilt wird.

Mit einer Art Behauptung as F

Der Typ Function ist zu breit. Ihre umbrochene Funktion muss ein Subtyp sein von: (...args: any[]) => any.

können Sie as F verwenden, um zu sagen, auf die zurück Funktion sein zuversichtlich zu Typoskript:

function log<F extends (...args: any[]) => any>(fn: F): F { 
    return ((...args: any[]) => { 
     console.log("Calling", fn.name); 
     return fn(...args); 
    }) as F 
} 

Mit einer Art Behauptung as any

Gleiche Umsetzung aber wir Function und as any statt (...args: any[]) => any verwenden können und as F (siehe die Antwort von Louis).

+0

Danke, ich dachte nicht über die Verwendung von Funktionsüberladungen wie folgt. – Aaron

+0

Ich habe mit der Idee des anderen Mitwirkenden bearbeitet. Der Typ 'Funktion' ist zu breit. Ihre umbrochene Funktion muss vom Typ sein: '(... args: any []) => any'. – Paleo

+0

Interessant, habe ich versucht 'F erweitert (...args: any []) => any' mit meinem ursprünglichen Code und es erlaubte mir immer noch nicht, mit dieser genauen Signatur aus irgendeinem Grund zurückzukehren, und 'wie F' funktionierte nicht mit' F extends Function'. Ehrlich gesagt verstehe ich nicht, warum das anders ist, aber es funktioniert. – Aaron

2

Die einfachste Änderung, die Sie machen können, ist die Art Ihrer Rückgabewert any zu erzwingen:

function log<F extends Function>(fn: F): F { 
    return ((...args: any[]) => { 
    console.log("Calling", fn.name); 
    return fn(...args); 
    }) as any; 
} 

Dies kompiliert Datei, und dies zu tun, Ihre setName Funktion die gleiche Signatur wie das, was haben Sie passieren zu log.

+0

Danke, ich fand das funktioniert, aber ich mag es nicht '' any'' zu verwenden ... auch, warum funktioniert 'as Function' nicht? – Aaron

+0

Die Verwendung von 'as any' ist nicht schlechter als' 'F' 'wie in der anderen Antwort. So oder so, Sie sagen dem Compiler "Vertrauen Sie mir, ich weiß, was ich mache". 'as Function' kann nicht funktionieren, weil' F' durch den übergebenen Parameter bestimmt wird. "loggen". Wenn 'F' eine Erweiterung von' Function' ist, kann man einer Variablen, die Objekte vom Typ 'Function' annehmen kann, ein Objekt vom Typ' F' zuweisen, aber ein Objekt vom Typ 'Function' einer Variablen zuweisen Objekte vom Typ 'F' sind nicht in Ordnung. Sie versuchen im Wesentlichen, Letzteres zu tun, wenn Sie 'als Funktion' anstelle von' wie irgendjemand' verwenden. – Louis

+0

Ich sehe, danke für die Erklärung. Das liegt hauptsächlich daran, dass Sie einem Untertyp keinen Basistyp zuordnen können. – Aaron

Verwandte Themen