136

TypeScript言語でメソッドのオーバーロードを行う方法はありますか?

私はこのようなことを達成したい:

class TestClass {
    someMethod(stringParameter: string): void {
        alert("Variant #1: stringParameter = " + stringParameter);
    }

    someMethod(numberParameter: number, stringParameter: string): void {
        alert("Variant #2: numberParameter = " + numberParameter + ", stringParameter = " + stringParameter);
    }
}

var testClass = new TestClass();
testClass.someMethod("string for v#1");
testClass.someMethod(12345, "string for v#2");

以下は、私がやりたくないことの例です (私は JS でハックをオーバーロードする部分が本当に嫌いです):

class TestClass {
    private someMethod_Overload_string(stringParameter: string): void {
        // A lot of code could be here... I don't want to mix it with switch or if statement in general function
        alert("Variant #1: stringParameter = " + stringParameter);
    }

    private someMethod_Overload_number_string(numberParameter: number, stringParameter: string): void {
        alert("Variant #2: numberParameter = " + numberParameter + ", stringParameter = " + stringParameter);
    }

    private someMethod_Overload_string_number(stringParameter: string, numberParameter: number): void {
        alert("Variant #3: stringParameter = " + stringParameter + ", numberParameter = " + numberParameter);
    }

    public someMethod(stringParameter: string): void;
    public someMethod(numberParameter: number, stringParameter: string): void;
    public someMethod(stringParameter: string, numberParameter: number): void;

    public someMethod(): void {
        switch (arguments.length) {
        case 1:
            if(typeof arguments[0] == "string") {
                this.someMethod_Overload_string(arguments[0]);
                return;
            }
            return; // Unreachable area for this case, unnecessary return statement
        case 2:
            if ((typeof arguments[0] == "number") &&
                (typeof arguments[1] == "string")) {
                this.someMethod_Overload_number_string(arguments[0], arguments[1]);
            }
            else if ((typeof arguments[0] == "string") &&
                     (typeof arguments[1] == "number")) {
                this.someMethod_Overload_string_number(arguments[0], arguments[1]);
            }
            return; // Unreachable area for this case, unnecessary return statement
        }
    }
}


var testClass = new TestClass();
testClass.someMethod("string for v#1");
testClass.someMethod(12345, "string for v#2");
testClass.someMethod("string for v#3", 54321);
4

5 に答える 5

212

仕様によると、TypeScript はメソッドのオーバーロードをサポートしていますが、非常に扱いにくく、パラメーターの型をチェックする多くの手作業が含まれています。プレーンな JavaScript でメソッドのオーバーロードに最も近いものには、そのチェックも含まれており、TypeScript は不要なランタイム パフォーマンス コストを回避するために実際のメソッド本体を変更しないようにしているためだと思います。

私が正しく理解していれば、最初に各オーバーロードのメソッド宣言を記述し、次にその引数をチェックしてどのオーバーロードが呼び出されたかを判断する1 つのメソッド実装を記述する必要があります。実装の署名は、すべてのオーバーロードと互換性がある必要があります。

class TestClass {
    someMethod(stringParameter: string): void;
    someMethod(numberParameter: number, stringParameter: string): void;

    someMethod(stringOrNumberParameter: any, stringParameter?: string): void {
        if (stringOrNumberParameter && typeof stringOrNumberParameter == "number")
            alert("Variant #2: numberParameter = " + stringOrNumberParameter + ", stringParameter = " + stringParameter);
        else
            alert("Variant #1: stringParameter = " + stringOrNumberParameter);
    }
}
于 2012-10-02T11:00:51.530 に答える
41

明確にするために更新します。TypeScript でのメソッドのオーバーロードは、表現する必要がある API を使用して既存のライブラリの型定義を作成できる限り、便利な機能です。

ただし、独自のコードを記述する場合は、オプションまたは既定のパラメーターを使用して、オーバーロードの認知オーバーヘッドを回避できる可能性があります。これは、メソッドのオーバーロードに代わるより読みやすい代替手段であり、直観的でない順序でオーバーロードを作成することを避けるため、API を正直に保ちます。

TypeScript オーバーロードの一般的な法則は次のとおりです。

オーバーロード シグネチャを削除でき、すべてのテストに合格する場合、TypeScript オーバーロードは必要ありません。

通常、オプションのパラメーターまたはデフォルトのパラメーターを使用して、または共用体型を使用して、またはオブジェクト指向を少し使用して、同じことを実現できます。

実際の質問

実際の質問では、次のオーバーロードが求められます。

someMethod(stringParameter: string): void {

someMethod(numberParameter: number, stringParameter: string): void {

個別の実装でオーバーロードをサポートする言語でも (注: TypeScript のオーバーロードは単一の実装を共有します)、プログラマーは順序付けの一貫性を提供するようアドバイスされています。これにより、署名が作成されます。

someMethod(stringParameter: string): void {

someMethod(stringParameter: string, numberParameter: number): void {

stringParameter常に必要なため、最初に実行されます。これを有効な TypeScript オーバーロードとして記述できます。

someMethod(stringParameter: string): void;
someMethod(stringParameter: string, numberParameter: number): void;
someMethod(stringParameter: string, numberParameter?: number): void {
    if (numberParameter != null) {
        // The number parameter is present...
    }
}

しかし、TypeScript オーバーロードの法則に従って、オーバーロード シグネチャを削除しても、すべてのテストは引き続きパスします。

someMethod(stringParameter: string, numberParameter?: number): void {
    if (numberParameter != null) {
        // The number parameter is present...
    }
}

実際の質問、実際の順序で

元の順序に固執する場合、オーバーロードは次のようになります。

someMethod(stringParameter: string): void;
someMethod(numberParameter: number, stringParameter: string): void;
someMethod(a: string | number, b?: string | number): void {
  let stringParameter: string;
  let numberParameter: number;

  if (typeof a === 'string') {
    stringParameter = a;
  } else {
    numberParameter = a;

    if (typeof b === 'string') {
      stringParameter = b;
    }
  }
}

パラメータをどこに配置するかを決めるには多くの分岐がありますが、ここまで読んでいるのであれば、この順序を維持したかったはずです... しかし待ってください、TypeScript のオーバーロードの法則を適用するとどうなるでしょうか?

someMethod(a: string | number, b?: string | number): void {
  let stringParameter: string;
  let numberParameter: number;

  if (typeof a === 'string') {
    stringParameter = a;
  } else {
    numberParameter = a;

    if (typeof b === 'string') {
      stringParameter = b;
    }
  }
}

すでに十分な分岐

もちろん、必要な型チェックの量を考えると...おそらく最良の答えは、単純に2つのメソッドを持つことです:

someMethod(stringParameter: string): void {
  this.someOtherMethod(0, stringParameter);
}

someOtherMethod(numberParameter: number, stringParameter: string): void {
  //...
}
于 2012-10-02T10:16:42.280 に答える
7

I wish. I want this feature too but TypeScript needs to be interoperable with untyped JavaScript which doesn't have overloaded methods. i.e. If your overloaded method is called from JavaScript then it can only get dispatched to one method implementation.

There\s a few relevant discussions on codeplex. e.g.

https://typescript.codeplex.com/workitem/617

I still think TypeScript should generate all the if'ing and switching so we wouldn't need to do it.

于 2013-07-20T14:11:28.080 に答える