TypeScript에서 메서드 오버로딩을 수행하는 방법이 있습니까?


109

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);

1
예, 기회가 있습니다. 언어는 아직 죽지 않았습니다. 또 다른 질문?
hakre

6
@hakre TypeScript가 이미 메서드 오버로딩을 지원한다는 점을 감안할 때 그것은 이상한 말입니다.
svick

@svick : 글쎄, 당신은 그 메소드 오버로딩이라고 부릅니까? 귀하의 답변에서 메서드 자체는 과부하가 걸리지 않습니다.
hakre

2
@hakre 사양에서는이를 메서드 오버로딩이라고합니다. 당신은 확실히 그것의 특히 좋은 버전이 아니라고 주장 할 수 있지만, 나는 그것이 전혀 존재하지 않는다고 말할 수 없다고 생각합니다.
svick

@svick : 나도 말하지 않았다. 그러나 OP가 묻는 기회는 메서드 오버로딩의 정신 모델에 대해 구체적으로 보입니다. 헤어 분할의 경우 메서드 서명 오버로딩이라고 말할 수 있습니다.)
hakre

답변:


165

사양에 따르면 TypeScript는 메서드 오버로딩을 지원하지만 매우 어색하고 매개 변수 유형을 확인하는 많은 수동 작업을 포함합니다. 일반 JavaScript에서 메서드 오버로딩에 가장 근접하게 접근 할 수있는 이유는 검사도 포함하고 TypeScript는 불필요한 런타임 성능 비용을 피하기 위해 실제 메서드 본문을 수정하지 않기 때문이라고 생각합니다.

내가 올바르게 이해했다면 먼저 각 오버로드에 대한 메서드 선언을 작성한 다음 인수를 확인하여 호출 된 오버로드를 결정하는 하나의 메서드 구현을 작성해야합니다. 구현 시그니처는 모든 오버로드와 호환되어야합니다.

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

3
@NicoVanBelle JavaScript는 메소드 오버로딩을 전혀 지원하지 않습니다. 그렇다면 JS로 돌아가는 것이 어떻게 도움이 될까요?
svick

인터페이스 확인은 어떻습니까? 그보다 더 나은 솔루션이 있습니까 : stackoverflow.com/questions/14425568/… ?
DiPix

흠 .. 나는 이것을 정말로 좋아하지 않는다. 대신에 선택적 매개 변수를 갖는 것이 읽는 것이 더 낫다.
LuckyLikey

3
여기서 중요한 것은 if 문을 입력하지 않고도 코드를 읽을 수 있도록 유지하는 것입니다. 그것이 무엇으로 변환되는지 누가 신경 쓰는지.
Brain2000

34

명확성을 위해 업데이트합니다. 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;
    }
  }
}

이미 충분한 분기

물론, 우리가해야 할 유형 검사의 양을 고려할 때 ... 아마도 가장 좋은 대답은 두 가지 방법을 갖는 것입니다.

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

someOtherMethod(numberParameter: number, stringParameter: string): void {
  //...
}

일반적으로 메서드 오버로딩으로 알려져 있지 않습니다. 또한 질문을 참조하십시오. 첫 번째 매개 변수의 유형이 변경됩니다.
hakre

3
나는 내 대답에서 선택적 매개 변수를 마지막에두면 number매개 변수가 두 번째 인수가되고 선택 사항이 될 것임을 인정했습니다. TypeScript는 "적절한"메서드 오버로드를 지원하지 않습니다.하지만 C # 세계조차도 대부분의 경우 더 읽기 쉬운 코드로 이어 지므로 오버로드에서 선택적 매개 변수로 이동하고 있습니다.
Fenton

당신은 의미 if (typeof numberParameter != 'undefined')오른쪽)
후안 멘데스에게

이는 사용 사례, 특히 0을 허용하는지 여부에 따라 다릅니다. 필요한 경우 !==저글링을 피하기 위해 사용 하는 것을 잊지 마십시오.
Fenton

1
@Sebastian은 종속성 주입 기회처럼 들립니다. TypeScript의 메서드 오버로딩에는 여러 데코레이션, 기본 매개 변수 및 공용체 유형이있는 단일 메서드가 포함되어 있으므로 더 나은 경험을 제공합니다. 메서드가보다 실질적인 방식으로 다른 경우 추상화를 사용하거나 여러 메서드를 구현합니다.
Fenton

7

나는 원한다. 이 기능도 원하지만 TypeScript는 오버로드 된 메서드가없는 형식화되지 않은 JavaScript와 상호 운용 될 수 있어야합니다. 즉, 오버로드 된 메서드가 JavaScript에서 호출되면 하나의 메서드 구현으로 만 전달 될 수 있습니다.

codeplex에 대한 관련 토론이 거의 없습니다. 예 :

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

나는 여전히 TypeScript가 모든 if'ing 및 스위칭을 생성해야하므로 그렇게 할 필요가 없다고 생각합니다.


2

선택적 속성 정의 인터페이스 를 함수 인수로 사용하지 않는 이유 ..

이 질문의 경우 일부 선택적 속성으로 정의 된 인라인 인터페이스를 사용하면 아래와 같은 코드를 직접 만들 수 있습니다.

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에서 제공되는 오버로딩은 다른 사람의 의견에서 언급했듯이 다른 정적 언어와 같은 해당 구현 코드를 지원하지 않고 함수의 다른 서명 목록 일 뿐이 기 때문입니다. 따라서 구현은 여전히 ​​하나의 함수 본문에서만 수행되어야하므로 Typescript에서 함수 오버로딩을 사용하는 것은 실제 오버로딩 기능을 지원하는 언어만큼 편안하지 않습니다.

그러나, 레거시 프로그래밍 언어에서는 사용할 수없는 타이프 스크립트로 제공되는 새롭고 편리한 것들이 여전히 많이 있습니다. 익명 인터페이스의 선택적 속성 지원은 레거시 함수 오버로딩에서 편안한 영역을 충족시키는 접근 방식이라고 생각합니다.


0

메서드 오버로드의 변형이 많은 경우 다른 방법은 모든 인수가 포함 된 클래스를 만드는 것입니다. 따라서 순서에 관계없이 원하는 매개 변수 만 전달할 수 있습니다.

class SomeMethodConfig {
  stringParameter: string;
  numberParameter: number;

 /**
 *
 */
 constructor(stringParameter: string = '012', numberParameter?: number) { // different ways to make a param optional
   this.numberParameter = 456; // you can put a default value here
   this.stringParameter = stringParameter; // to pass a value throw the constructor if necessary
 }
}

또한 기본값으로 생성자를 만들거나 일부 필수 인수를 전달할 수 있습니다. 그런 다음 다음과 같이 사용하십시오.

const config = new SomeMethodConfig('text');
config.numberParameter = 123; // initialize an optional parameter only if you want to do it
this.SomeMethod(config);

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.