program story

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

inputbox 2020. 8. 19. 08:02
반응형

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

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

If I understand it correctly, you have to first write a method declaration for each of the overloads and then one method implementation that checks its arguments to decide which overload was called. The signature of the implementation has to be compatible with all of the overloads.

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

Update for clarity. Method overloading in TypeScript is a useful feature insofar as it allows you to create type definitions for existing libraries with an API that needs to be represented.

When writing your own code, though, you may well be able to avoid the cognitive overhead of overloads using optional or default parameters. This is the more readable alternative to method overloads and also keeps your API honest as you'll avoid creating overloads with unintuitive ordering.

The general law of TypeScript overloads is:

If you can delete the overload signatures and all of your tests pass, you don’t need TypeScript overloads

You can usually achieve the same thing with optional, or default parameters - or with union types, or with a bit of object-orientation.

The Actual Question

The actual question asks for an overload of:

someMethod(stringParameter: string): void {

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

Now even in languages that support overloads with separate implementations (note: TypeScript overloads share a single implementation) - programmers are advices to provide consistency in ordering. This would make the signatures:

someMethod(stringParameter: string): void {

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

The stringParameter is always required, so it goes first. You could write this as a working TypeScript overload:

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

But following the law of TypeScript overloads, we can delete the overload signatures and all our tests will still pass.

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

The Actual Question, In the Actual Order

If you were determined to persist with the original order, the overloads would be:

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

Now that's a lot of branching to work out where to put the parameters, but you really wanted to preserve this order if you are reading this far... but wait, what happens if we apply the law of TypeScript overloads?

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

Enough Branching Already

Of course, given the amount of type checking we need to do... maybe the best answer is simply to have two method:

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

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

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.


Why not to use optional property defined interface as the function argument..

For the case in this question, using an inline interface defined with some optional properties only could directly make code like something below:

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

Because overloading provided in TypeScript is, as mentioned in others' comments, just a list of function's different signatures without supporting corresponding implementation codes like other static languages. So the implementation still have to be done in only one function body, which makes the usage of function overloading in Typescript not as comfortable as such languages supporting the real overloading feature.

However, there is still many new and convenient stuffs provided in typescript which is not available in legacy programming language, where optional property support in an anonymous interface is such an approach to meet the comfortable zone from the legacy function overloading, I think.


Javascript does not have any concept of overloading. Typescript is not c# or Java.

But you can implement overloading in Typescript.

Read this post http://www.gyanparkash.in/function-overloading-in-typescript/

참고URL : https://stackoverflow.com/questions/12688275/is-there-a-way-to-do-method-overloading-in-typescript

반응형