2015-04-23 12 views
13

Poszukuję możliwości przekazania metody klasy do funkcji, która następnie może wykonać tę funkcję na instancji tej klasy. coś w tym Pseudokod: (należy pamiętać, że jest to abstrakcyjny przykład)Przekazywanie metody klasy jako parametru w maszynopisie

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 

Czy istnieje możliwośc to zrobić?

wiem, mogę robić coś takiego:

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 

ale wiąże statycznych funkcji, które nie chcę.

Odpowiedz

0

Javascript pozwoliłby na to, ale nie byłby pewien, czy tego właśnie chcesz?

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

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

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

Tak, że będzie działać, ale nie uzyskać korzyści z maszynopisu sprawdzenie, czy 'someFunc()' jest faktycznie zdefiniowany w 'Foo'. – xDreamCoding

3

Jestem zakładając szukasz jakiś sposób dla kompilatora maszynopis do wyegzekwowania, że ​​dana funkcja istnieje na Foo? Niestety, nie sądzę, żeby można to było zrobić. Może innym guru maszynopis może przyjść tutaj i odpowiedzieć bardziej konkretnie, ale jestem prawie pewien, że to najbliżej, które można uzyskać:

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

Masz rację, miałem nadzieję, że w maszynopisie był sposób, aby kompilator sprawdził, czy dana funkcja istnieje w klasie. Dziękuję za odpowiedź, ale nie wiedziałem, że możesz wywołać funkcję takiego obiektu: 'obj [" functionname "]()' – xDreamCoding

+0

Niesamowita odpowiedź. Wielkie dzięki – suku

12

To nie w czasie kompilacji sprawdzić, że funkcja pochodzi z Foo, ale robi reszta:

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

Tak, funkcja zadeklarować tak:

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

nazywają go tak od maszynopisu:

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

Albo z javascript:

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

Ponadto można przejść metoda:

myfunction(this.someMethod); 
1

Typescript 2+ rozwiązanie

TL; DR: TypeScript Playground, Repo with a demo

Zalety:

  1. Sprawdzanie czasu kompilacji.
  2. Nie pozwoli Ci zgubić this kontekstu, gdy przekazuje metodę instancji.
  3. Nie trać wydajności: nie musisz deklarować metod klas jako metod instancji (np. public somefunc =() => { return this.prop; }) - Learn more.
  4. Nie zadzieraj z prototypem klasy.
  5. Konsekwentny wzór sygnatury: przekazywanie wywołania zwrotnego jako pierwszego argumentu i thisArg jako drugiego (np. Array.prototype.map()).

Rozważmy następujący kod:

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 

zwrócić uwagę na podpisanie Foo#func:

public func(this: Foo): number 

Stwierdza, że ​​ta funkcja powinna być wywoływana w kontekście klasy instancji . Jest to pierwsza część rozwiązania, która nie pozwoli Ci zgubić kontekstu.

Druga część jest bar funkcja przeciążenia:

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 

byłoby to pozwalają przekazać funkcje rodzajowe, a także metody instancji.

Możesz dowiedzieć się więcej na temat tych zagadnień w maszynopisie Handbook:

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