web-dev-qa-db-ja.com

Typescriptのパラメーターとしてクラスメソッドを渡す

クラスメソッドを関数に渡し、そのクラスのインスタンスでその関数を実行できる可能性を探しています。その擬似コードのようなもの:(これは抽象的な例であることに注意してください)

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

これを行う可能性はありますか?

私はそのようなことをしている可能性があることを知っています:

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

しかし、それは私が望んでいない静的関数を伴います。

25
xDreamCoding

これは、関数がFooから来たことをコンパイル時にチェックしませんが、残りは行います:

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
18
Ryan Cavanaugh

TypeScript 2+ソリューション

TL; DRTypeScript Playgroundデモ付きのレポ

利点:

  1. コンパイル時のチェック。
  2. インスタンスのメソッドを渡すときにthisコンテキストを失ってはいけません。
  3. パフォーマンスを失わないでください。クラスのメソッドをインスタンスメソッドとして宣言する必要はありません(例:public somefunc = () => { return this.prop; })- 詳細
  4. クラスのプロトタイプを台無しにしないでください。
  5. 一貫した署名パターン:最初の引数としてコールバックを渡し、2番目の引数としてthisArgを渡します(例: Array.prototype.map() )。

次のコードを検討してください。

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

Foo#funcの署名に注意を向けます。

public func(this: Foo): number

この関数は、クラスのインスタンスのコンテキストで呼び出す必要があることを示しています。これは、thisコンテキストを失わないソリューションの最初の部分です。

2番目の部分は、bar関数のオーバーロードです。

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

これにより、ジェネリック関数とインスタンスメソッドを渡すことができます。

これらのトピックの詳細については、TypeScriptハンドブックをご覧ください。

  1. thisコールバックのパラメーター
  2. 関数のオーバーロード
  3. ジェネリック
9
Deilan

TypeScriptコンパイラが特定の関数がFooに存在することを強制する方法を探していると思いますか?残念ながら、それを行う方法はないと思います。別のTypeScriptの第一人者がここに来て、より具体的に答えることができるかもしれませんが、これが最も近いと確信しています。

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
3
thetoast

はい、次のような関数を宣言します:

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

TypeScriptから次のように呼び出します。

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

またはjavascriptから:

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

メソッドを渡すこともできます:

myfunction(this.someMethod);
1
devi

Javascriptはこれを許可しますが、それがあなたが望むものかどうかはわかりませんか?

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

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

console.log(bar("new Foo().someFunc('erik')"));
1
Erik Lieben