TypeScriptコールバックタイプの定義


172

TypeScriptには次のクラスがあります。

class CallbackTest
{
    public myCallback;

    public doWork(): void
    {
        //doing some work...
        this.myCallback(); //calling callback
    }
}

私はこのようなクラスを使用しています:

var test = new CallbackTest();
test.myCallback = () => alert("done");
test.doWork();

コードが機能するため、期待どおりにメッセージボックスが表示されます。

私の質問は:私のクラスフィールドに提供できるタイプはありますmyCallbackか?現在、publicフィールドmyCallbackany上記のタイプです。コールバックのメソッドシグネチャを定義するにはどうすればよいですか?または、タイプをある種のコールバックタイプに設定できますか?または私はこれらのネザーを行うことができますか?any(暗黙/明示)を使用する必要がありますか?

私はこのようなものを試しましたが、うまくいきませんでした(コンパイル時エラー):

public myCallback: ();
// or:
public myCallback: function;

これについてはオンラインで説明が見つからなかったので、助けていただければ幸いです。

回答:


211

TypeScript言語仕様で何か見つけたところですが、それはかなり簡単です。かなり近かった。

構文は次のとおりです。

public myCallback: (name: type) => returntype;

私の例では、それは

class CallbackTest
{
    public myCallback: () => void;

    public doWork(): void
    {
        //doing some work...
        this.myCallback(); //calling callback
    }
}

8
コールバック署名を定義するためにパラメーター名が必要な理由が
わかりませ

4
C#チームの文化遺産かもしれないと思いますが、結局気に入っていると思います...
2grit

ドキュメントのそのページへのリンクを@nikeeeに提供できますか?
jcairney 2017


147

さらに一歩進むには、次のように関数シグネチャへの型ポインタを宣言できます。

interface myCallbackType { (myArgument: string): void }

次のように使用します。

public myCallback : myCallbackType;

9
これは(IMO)受け入れられた回答よりもはるかに優れたソリューションです。これにより、型を定義し、たとえば、その型のパラメーター(コールバック)を渡して、それを呼び出すことを含め、任意の方法で使用できるようになるためです。受け入れられた回答はメンバー変数を使用し、メンバー変数を関数に設定してからメソッドを呼び出す必要があります。最初に変数を設定することはメソッドを呼び出す契約の一部であるため、醜く、エラーが発生しやすくなります。
デビッド

また、あなたが簡単に例えば、nullとしてコールバックを設定することができますlet callback: myCallbackType|null = null;
Doches

1
TSLintは「TSLint:インターフェイスには呼び出しシグネチャしかありません。使用してください。type MyHandler = (myArgument: string) => void代わりにしてください。(callable-types)」TSVの回答を
Arjan

この回答の以前のドラフトは、実際に私がこの質問に導いた問題を解決しました。コンパイラエラーを生成せずに任意の数のパラメータを受け入れることができるインターフェイス内で、十分に寛容な関数シグネチャを定義しようとしていました。私の場合の答えはを使用すること...args: any[]でした。例:エクスポートインターフェイスMyInterface {/ **コールバック関数。/ callback:(... args:any [])=> any、/ *コールバック関数のパラメーター。* / callbackParams:any []}
Ken Lyon

61

新しいタイプを宣言できます:

declare type MyHandler = (myArgument: string) => void;

var handler: MyHandler;

更新。

declareキーワードは必要ありません。.d.tsファイルまたは同様の場合に使用する必要があります。


このドキュメントはどこにありますか?
E.サンディン、2016年

セクション「タイプの別名」 - E.Sundin @ typescriptlang.org/docs/handbook/advanced-types.html
TSV

1
真実でありながら知ってはいますが、同じページ(現在)には「ソフトウェアの理想的なプロパティが拡張可能になっているため、可能な場合は常に型エイリアスよりもインターフェイスを使用する必要があります」と記載されています。
2016年

@Arjan-オブジェクトについてはこれに完全に同意します。特定していただけませんか-関数をどのように拡張しますか?
TSV

型宣言はオプションであることに注意してください:var handler: (myArgument: string) => void構文的に有効です(少し乱雑な場合)。
ハッチ

35

次に例を示します。パラメータを受け入れず、何も返しません。

class CallbackTest
{
    public myCallback: {(): void;};

    public doWork(): void
    {
        //doing some work...
        this.myCallback(); //calling callback
    }
}

var test = new CallbackTest();
test.myCallback = () => alert("done");
test.doWork();

パラメータを受け入れる場合は、それも追加できます。

public myCallback: {(msg: string): void;};

また、値を返したい場合は、それも追加できます。

public myCallback: {(msg: string): number;};

機能的には同じです。同じものを定義し、関数のシグネチャの型チェックを提供します。どちらでもお使いいただけます。仕様はそうだと言っていますexactly equivalent
フェントン2012年

6
@nikeee:問題はあなたの答えと何が違うのですか?スティーブはあなたの前に彼の答えを投稿しました。
jgauffin 2014年

@jgauffin確かに、結果は同じです。Steveのバージョンではインターフェイス定義全体が許可されているため、コールバックについて話すとき、私が投稿したソリューションのIMOはより自然です。それはあなたの好みに依存します。
nikeee 2014年

@フェントンは、そのドキュメントへのリンクを提供していただけませんか?
jcairney 2017

17

ジェネリック関数が必要な場合は、以下を使用できます。どこにも文書化されていないようですが。

class CallbackTest {
  myCallback: Function;
}   

3

次のものを使用できます。

  1. タイプエイリアス(typeキーワードを使用し、関数リテラルにエイリアスを付ける)
  2. インターフェース
  3. 関数リテラル

これらの使用例を次に示します。

type myCallbackType = (arg1: string, arg2: boolean) => number;

interface myCallbackInterface { (arg1: string, arg2: boolean): number };

class CallbackTest
{
    // ...

    public myCallback2: myCallbackType;
    public myCallback3: myCallbackInterface;
    public myCallback1: (arg1: string, arg2: boolean) => number;

    // ...

}

1

イベントリスナーにコールバックを追加しようとしたときに同じエラーに遭遇しました。奇妙なことに、コールバックタイプをEventListenerに設定すると解決しました。関数シグネチャ全体を型として定義するよりもエレガントに見えますが、これが正しい方法であるかどうかはわかりません。

class driving {
    // the answer from this post - this works
    // private callback: () => void; 

    // this also works!
    private callback:EventListener;

    constructor(){
        this.callback = () => this.startJump();
        window.addEventListener("keydown", this.callback);
    }

    startJump():void {
        console.log("jump!");
        window.removeEventListener("keydown", this.callback);
    }
}

いいね。しかし、他のクラスはどこで活動していますか?
Yaro

1

私は少し遅れましたが、TypeScriptで少し前から、コールバックのタイプを定義することができます

type MyCallback = (KeyboardEvent) => void;

使用例:

this.addEvent(document, "keydown", (e) => {
    if (e.keyCode === 1) {
      e.preventDefault();
    }
});

addEvent(element, eventName, callback: MyCallback) {
    element.addEventListener(eventName, callback, false);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.