2015-04-23 13 views
13

Sto cercando la possibilità di passare un metodo di classe a una funzione che quindi può eseguire quella funzione su un'istanza di quella classe. Qualcosa del genere pseudocodice: (si noti che questo è un esempio astratto)Passare il metodo di classe come parametro nel dattiloscritto

class Foo { 
    public somefunc() { 
     // do some 
    } 
    public anyfunc() { 
     // do any 
    } 
} 

function bar(obj: Foo ,func: "Foo.method") { // "that's what im looking for" 
    obj.func(); 
} 

bar(new Foo(), Foo.somefunc); // do some 
bar(new Foo(), Foo.anyfunc); // do any 

C'è un possiblity per fare questo?

So che avrei potuto fare qualcosa di simile:

class Foo { 
    static somefunc(fooObj: Foo) { 
     // do some 
    } 
    static anyfunc(fooObj: Foo) { 
     // do any 
    } 
} 

interface func { 
    (fooObj: Foo); 
} 

function bar(obj: Foo, fn: func) { 
    fn(obj); 
} 

bar(new Foo(), Foo.somefunc); // do some 
bar(new Foo(), Foo.anyfunc); // do any 

ma che coinvolge funzioni statiche, che non voglio.

risposta

0

Javascript consentirebbe questo, ma non è sicuro se questo è quello che vuoi?

class Foo { 
public someFunc(name:string){ 
    return "Hello, " + name; 
} 

function bar(funcName: string) { 
    return eval(funcName); 
} 

console.log(bar("new Foo().someFunc('erik')")); 
+0

Sì che avrebbe funzionato, ma non vorrei ottenere il beneficio di dattiloscritto controllando che 'someFunc()' sia effettivamente definito su 'Foo'. – xDreamCoding

3

Suppongo che stai cercando un modo per il compilatore TypeScript per far rispettare la funzione data su Foo? Sfortunatamente, non penso che ci sia un modo per farlo. Forse un altro guru dattiloscritto può venire qui e rispondere più concretamente, ma sono abbastanza sicuro che questo è il più vicino che si può ottenere:

class Foo { 
    constructor(private name:string) { } 

    public somefunc() { 
     console.log("someFunc called on", this.name); 
    } 
    public anyfunc() { 
     console.log("anyFunc called on", this.name); 
    } 
} 

function bar(obj: Foo, func: string) { 
    if (obj[func] && obj[func] instanceof Function) { 
     obj[func](); 
    } else { 
     throw new Error("Function '" + func + "' is not a valid function"); 
    } 
} 

bar(new Foo("foo1"), "somefunc"); // output: 'somefunc called on foo1' 
bar(new Foo("foo2"), "anyfunc"); // output: 'anyfunc called on foo1' 
bar(new Foo("foo3"), "badFunction"); // throws: Error: Function 'badFunction' is not a valid function 
+0

Hai ragione, speravo che il dattiloscritto fosse un modo per consentire al compilatore di verificare se la funzione data esiste sulla classe. Grazie per la risposta, però, non sapevo che si potesse chiamare una funzione di un oggetto del genere: 'obj [" functionname "]()' – xDreamCoding

+0

Risposta stupenda. molte grazie – suku

12

Questo controllo non a tempo di compilazione che la funzione è venuto da un Foo, ma fa il resto:

class Foo { 
    public somefunc() { 
     // do some 
    } 
    public anyfunc() { 
     // do any 
    } 
} 

function bar(obj: Foo ,func:() => void) { 
    func.call(obj); 
} 

bar(new Foo(), Foo.prototype.somefunc); // do some 
bar(new Foo(), Foo.prototype.anyfunc); // do any 
1

Sì, la funzione di dichiarare come questo:

myfunction(action:() => void){ 
    action(); 
} 

chiamare in questo modo da dattiloscritto:

myfunction(() => alert("hello")); 

O dalla javascript:

myfunction(function() { alert("hello"); }); 

Inoltre è possibile passare metodo:

myfunction(this.someMethod); 
1

tipografico 2+ soluzione

TL; DR: TypeScript Playground, Repo with a demo

Vantaggi:

  1. fase di compilazione controllo.
  2. Non ti lascerà perdere il contesto this quando passa il metodo di un'istanza.
  3. Non perdere prestazioni: non è necessario dichiarare metodi di classe come metodi di istanza (ad esempio public somefunc =() => { return this.prop; }) - Learn more.
  4. Non scherzare con il prototipo di una classe.
  5. Modello di firma coerente: passaggio di un callback come primo argomento e thisArg come secondo (ad esempio Array.prototype.map()).

Si consideri il seguente codice:

class Foo { 
    private result: number = 42; 

    public func(this: Foo): number { 
     return this.result; 
    } 
} 

function action(): void { 
    console.log("Hello world!"); 
} 

function bar(callbackFn: (this: void) => any, thisArg?: undefined): any; 
function bar<T>(callbackFn: (this: T) => any, thisArg: T): any; 
function bar<T, TResult>(callbackFn: (this: T) => TResult, thisArg: T): TResult { 
    return callbackFn.call(thisArg); 
} 

const foo = new Foo(); 

bar(action); // success 
bar(foo.func); // ERROR: forgot to pass `thisArg` 
bar(foo.func, foo); // success 

rivolgere la vostra attenzione alla firma di Foo#func:

public func(this: Foo): number 

Essa afferma che questa funzione dovrebbe essere invocato in un contesto di classe istanza . Questa è la prima parte della soluzione che non ti lascerà perdere il contesto this.

La seconda parte è bar sovraccarichi funzionali:

function bar(callbackFn: (this: void) => any, thisArg?: undefined): any; 
function bar<T>(callbackFn: (this: T) => any, thisArg: T): any; 
function bar<T, TResult>(callbackFn: (this: T) => TResult, thisArg: T): TResult 

Questo li lascerebbe passate di funzioni generiche così come metodi di istanza.

È possibile saperne di più su questi argomenti a macchina Handbook:

  1. this parameters in callbacks
  2. Function overloads
  3. Generics
Problemi correlati