web-dev-qa-db-ja.com

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

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);
99
Void-995

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

私がそれを正しく理解している場合、まず各オーバーロードのメソッド宣言を作成し、次に引数をチェックして呼び出されたオーバーロードを決定するoneメソッド実装を作成する必要があります。実装の署名は、すべてのオーバーロードと互換性がなければなりません。

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);
    }
}
141
svick

明確にするために更新します。 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 {
  //...
}
28
Fenton

私は望む。この機能も必要ですが、TypeScriptは、オーバーロードされたメソッドを持たない型指定のないJavaScriptと相互運用できる必要があります。つまり、オーバーロードされたメソッドがJavaScriptから呼び出された場合、1つのメソッド実装にのみディスパッチできます。

Codeplexに関するいくつかの関連する議論があります。例えば.

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

TypeScriptはすべてのif'ingと切り替えを生成する必要があるので、それを行う必要はないと思います。

8
nicopolyptic

Javascriptにはオーバーロードの概念はありません。 TypeScriptはc#またはJavaではありません。

ただし、TypeScriptでオーバーロードを実装できます。

この投稿を読む http://www.gyanparkash.in/function-overloading-in-TypeScript/

2
Gyan

オプションのプロパティ定義インターフェイス を関数の引数として使用しない理由.

この質問の場合、いくつかのオプションプロパティで定義されたインラインインターフェイスを使用すると、以下のようなコードを直接作成できます。

class TestClass {

    someMethod(arg: { stringParameter: string, numberParameter?: number }): void {
        let numberParameterMsg = "Variant #1:";
        if (arg.numberParameter) {
            numberParameterMsg = `Variant #2: numberParameter = ${arg.numberParameter},`;
        }
        alert(`${numberParameterMsg} stringParameter = ${arg.stringParameter}`);
    }
}

var testClass = new TestClass();
testClass.someMethod({ stringParameter: "string for v#1" });
testClass.someMethod({ numberParameter: 12345, stringParameter: "string for v#2" });

TypeScriptで提供されるオーバーロードは、他のコメントで述べられているように、他の静的言語のような対応する実装コードをサポートすることなく、関数の異なるシグネチャのリストにすぎないためです。したがって、実装は1つの関数本体でのみ行う必要があり、TypeScriptでの関数のオーバーロードの使用は、実際のオーバーロード機能をサポートする言語ほど快適ではありません。

ただし、TypeScriptには、レガシープログラミング言語では利用できない新しい便利なものがまだ多くあります。匿名インターフェイスでのオプションのプロパティサポートは、レガシー関数のオーバーロードから快適なゾーンを満たすためのアプローチです。

1
千木郷