TypeScript 함수 오버로딩


243

TypeScript 언어 사양의 섹션 6.3에서는 함수 오버로드에 대해 설명하고이를 구현하는 방법에 대한 구체적인 예를 제공합니다. 그러나 내가 이와 같은 것을 시도하면 :

export class LayerFactory { 

    constructor (public styleFactory: Symbology.StyleFactory) { }

    createFeatureLayer (userContext : Model.UserContext, mapWrapperObj : MapWrapperBase) : any {           
         throw "not implemented";
    }                 

    createFeatureLayer(layerName : string, style : any) : any {
        throw "not implemented";
     }        

}

함수 매개 변수의 유형이 다르더라도 중복 식별자를 나타내는 컴파일러 오류가 발생합니다. 두 번째 createFeatureLayer 함수에 추가 매개 변수를 추가하더라도 여전히 컴파일러 오류가 발생합니다. 아이디어주세요.


답변:


189

두 함수가 JavaScript로 컴파일 될 때 서명이 완전히 동일하기 때문일 수 있습니다. JavaScript에는 유형이 없으므로 동일한 개수의 인수를 사용하는 두 개의 함수를 만듭니다. 따라서 TypeScript는 이러한 함수를 만들 수 없도록 제한합니다.

TypeScript는 많은 매개 변수를 기반으로 오버로드를 지원하지만 OO 언어와 비교하면 따라야 할 단계가 약간 다릅니다. 다른 SO 질문에 대한 답변으로 누군가가 좋은 예를 들어 설명했습니다 : Method overloading? .

기본적으로 우리가하고있는 일은 TypeScript가 컴파일 오류를주지 않도록 하나의 함수와 많은 선언을 만드는 것입니다. 이 코드가 JavaScript로 컴파일되면 구체적인 기능 만 표시됩니다. 여러 인수를 전달하여 JavaScript 함수를 호출 할 수 있으므로 작동합니다.


50
이를 지원하기 위해 언어를 수정할 수 있습니다. 이론적으로 컴파일 된 TypeScript (예 : createFeatureLayer_1 및 createFeatureLayer_2)에 의해 이름이 지정되고 호출 된 함수 구현을 생성 할 수 있으며 createFeatureLayer는 바닐라 JavaScript와의 상호 운용을 위해 인수의 내용을 기반으로 호출 할 함수를 결정할 수 있습니다.
토마스 에스 트리 아스

8
TypeScript에서 오버로드는 매개 변수 수를 기준으로 만 가능한 것처럼 말하고 유형을 기반으로 한 오버로드는 Steve Fenton의 답변에 표시된 것처럼 가능합니다.
Matthijs Wessels

9
이것은 일종의 절름발이입니다. TypeScript는 실제로 전달 된 내용에 따라 고유하게 명명 된 구현을 선택하는 "메타 함수"를 생성해야합니다. 컴파일러를 전달할 수있는 균열이 있지만 유형 스니핑의 구현이 올바르지 않을 수 있습니다.
에스겔 빅터

5
@EzekielVictor TypeScript는 런타임에 유형을 확인하는 안정적인 방법이 있다면 그렇게 할 것입니다.
thorn̈

3
그것은 훨씬 더 복잡하고 JavaScript 유형으로 가능하지만 인터페이스, types, enum, generics 등과 같은 TS 관련 개념 은 런타임에 손실됩니다. 그래서 당신이 할 수없는 이유 someObject instanceof ISomeInterfaceDefinedInTypeScript입니다.
Morgan Touverey Quilling

209

TypeScript에서 오버로드하면 여러 서명이있는 구현이 하나만 있습니다.

class Foo {
    myMethod(a: string);
    myMethod(a: number);
    myMethod(a: number, b: string);
    myMethod(a: any, b?: string) {
        alert(a.toString());
    }
}

TypeScript에서는 세 가지 오버로드 만 실제 구현이 아니라 메서드 호출의 가능한 서명으로 인식합니다.

귀하의 경우 매개 변수에 공통성이 충분하지 않기 때문에 이름이 다른 두 가지 방법을 개인적으로 사용하기 때문에 방법 본문에 수행 할 작업을 결정하기 위해 많은 "ifs"가 필요할 수 있습니다.

TypeScript 1.4

TypeScript 1.4부터는 일반적으로 공용체 유형을 사용하여 과부하가 필요하지 않습니다. 위의 예는 다음을 사용하여 더 잘 표현 될 수 있습니다.

myMethod(a: string | number, b?: string) {
    alert(a.toString());
}

유형 a은 " string또는 number"입니다.


좋은 대답입니다. 강조하고 싶습니다. 다음과 같은 이유로 과부하하려고 할 때 유용하지 않을 수 있습니다. 같은 생성자를 사용하여 모든 예상 속성을 정의하는 객체를 전달할 수있는 인스턴스를 갖고 싶습니다. 한 가지 사례는 개별 매개 변수를 전달하는 것입니다. class Foo { constructor(obj) { } constructor (a: number, b: string, c: boolean) {} }
Hlawuleka MAS

이 전화 할 경우 지점에 대한 필요가 없습니다 - 일반적으로, 차라리 객체를 나에게 각 방법을 만들 공장 방법을 사용하는 것 Foo.fromObject(obj)Foo.fromJson(str)등등.
Fenton

그러나 그것은 매개 변수를 항상 객체 또는 단일 문자열로 전달한다고 가정합니다. 이전 의견에서 강조 표시된 것처럼 매개 변수를 별도로 전달하려면 어떻게해야합니까? Foo.methos(1, 2, 3) Foo.method(1) Foo.method(Obj) 또한 Foo클래스, fromObject 및 fromJson 에 다른 메소드가 있음을 알았습니다.
Hlawuleka MAS

1
그 차이를 소스로 되 돌리면 보통 필요하지 않다는 것을 알게 될 것입니다. 예를 들어, 입력 myNum하거나 myObj어쨌든해야하므로 별도의 방법을 사용하지 않고 모든 것을 명확하게 만들고 불필요한 분기 논리를 피하십시오.
Fenton

2
매개 변수에 따라 다른 리턴 유형을 사용하려는 경우 공용체 유형을 사용하면 문제가 발생할 수 있습니다. 반환 유형이 항상 매개 변수 유형 중 하나와 일치하면 제네릭으로 해결할 수 있지만 다른 경우에는 과부하가 가장 좋은 솔루션입니다.
존 몽고메리

45

함수를 여러 호출 서명이있는 유형으로 선언 하여 오버로드 된 함수를 선언 수 있습니다 .

interface IFoo
{
    bar: {
        (s: string): number;
        (n: number): string;
    }
}

그런 다음 다음을 수행하십시오.

var foo1: IFoo = ...;

var n: number = foo1.bar('baz');     // OK
var s: string = foo1.bar(123);       // OK
var a: number[] = foo1.bar([1,2,3]); // ERROR

함수 의 실제 정의 는 단수 여야하며 인수에서 내부적으로 적절한 디스패치를 ​​수행해야합니다.

예를 들어, 클래스를 사용하면 (구현할 수는 IFoo있지만 필요하지는 않음) :

class Foo
{
    public bar(s: string): number;
    public bar(n: number): string;
    public bar(arg: any): any 
    {
        if (typeof(arg) === 'number')
            return arg.toString();
        if (typeof(arg) === 'string')
            return arg.length;
    }
}

여기서 흥미로운 점은 any양식 이보다 구체적으로 입력 된 재정의에 의해 숨겨져 있다는 것 입니다.

var foo2: new Foo();

var n: number = foo2.bar('baz');     // OK
var s: string = foo2.bar(123);       // OK
var a: number[] = foo2.bar([1,2,3]); // ERROR

1

일반적으로 함수 오버로딩이란 무엇입니까?

함수 오버로딩 또는 메서드 오버로딩은 구현다른 동일한 이름여러 함수 를 생성 하는 기능 입니다 ( Wikipedia )


JS에서 함수 오버로딩이란 무엇입니까?

JS에서는이 기능을 사용할 수 없습니다. 여러 선언의 경우 마지막으로 정의 된 함수가 사용됩니다.

function foo(a1, a2) { return `${a1}, ${a2}` }
function foo(a1) { return `${a1}` } // replaces above `foo` declaration
foo(42, "foo") // "42"

... 그리고 TS?

오버로드 는 JS 런타임에 영향을 미치지 않는 컴파일 타임 구성입니다.

function foo(s: string): string // overload #1 of foo
function foo(s: string, n: number): number // overload #2 of foo
function foo(s: string, n?: number): string | number {/* ... */} // foo implementation

위 코드를 사용하면 중복 구현 오류가 발생합니다 (JS보다 안전). TS는 첫 번째 피팅 과부하를 하향식으로 선택하므로 과부하는 가장 구체적인 것부터 가장 광범위한 것까지 정렬됩니다.


TS에서 메소드 오버로드 :보다 복잡한 예

오버로드 된 클래스 메소드 유형은 오버로드 기능과 유사한 방식으로 사용될 수 있습니다.

class LayerFactory {
    createFeatureLayer(a1: string, a2: number): string
    createFeatureLayer(a1: number, a2: boolean, a3: string): number
    createFeatureLayer(a1: string | number, a2: number | boolean, a3?: string)
        : number | string { /*... your implementation*/ }
}

const fact = new LayerFactory()
fact.createFeatureLayer("foo", 42) // string
fact.createFeatureLayer(3, true, "bar") // number

함수 구현이 컴파일러에 의해 시행되는 모든 과부하 서명과 호환되므로 매우 다른 과부하가 가능합니다.

더 많은 정보 :


0

다른 사람들에게 앞서서, 나는 WebPack이 Angular 2 용으로 컴파일 한 TypeScript에 의해 명시 된 것처럼 오버로드 된 메소드 대신 조용히 overWRITTEN을 얻는 것을 관찰했습니다.

myComponent {
  method(): { console.info("no args"); },
  method(arg): { console.info("with arg"); }
}

부름:

myComponent.method()

인수가없는 메소드를 실행하고 출력이없는 인수 없음 버전을 자동으로 무시하는 것 같습니다.

with arg

2
오버로드에 대해 별도의 본문을 선언 할 수 없으며 서명 만 다릅니다.
adharris

5
사용중인 TypeScript 컴파일러 버전이 확실하지 않지만 현재 버전에서는 Duplicate function implementation이와 같은 코드에 대한 경고 가 표시됩니다.
Royston Shufflebotham

0

타입 스크립트에서 함수 오버로딩 :

Wikipedia (및 많은 프로그래밍 서적)에 따르면 메소드 / 함수 오버로드의 정의는 다음과 같습니다.

일부 프로그래밍 언어에서 함수 오버로드 또는 메소드 오버로드는 구현이 다른 동일한 이름의 여러 함수를 작성할 수있는 기능입니다 . 오버로드 된 함수에 대한 호출은 호출 컨텍스트에 적합한 해당 기능의 특정 구현을 실행하여 하나의 함수 호출이 컨텍스트에 따라 다른 작업을 수행 할 수 있도록합니다.

타입 스크립트에서는 인자의 수와 타입에 따라 호출되는 동일한 함수의 다른 구현을 가질 수 없습니다. TS를 JS로 컴파일 할 때 JS의 함수는 다음과 같은 특성을 갖기 때문입니다.

  • JavaScript 함수 정의는 매개 변수에 대한 데이터 유형을 지정하지 않습니다
  • JavaScript 함수는 호출 될 때 인수 수를 확인하지 않습니다

따라서 엄격한 의미에서 TS 함수 과부하가 존재하지 않는다고 주장 할 수 있습니다. 그러나 TS 코드 내에서 기능 과부하를 완벽하게 흉내낼 수있는 작업이 있습니다.

예를 들면 다음과 같습니다.

function add(a: number, b: number, c: number): number;
function add(a: number, b: number): any;
function add(a: string, b: string): any;

function add(a: any, b: any, c?: any): any {
  if (c) {
    return a + c;
  }
  if (typeof a === 'string') {
    return `a is ${a}, b is ${b}`;
  } else {
    return a + b;
  }
}

TS 문서는이 메소드 오버로딩을 호출하며, 기본적으로 우리가 한 일은 TS 컴파일러에 여러 메소드 서명 (가능한 매개 변수 및 유형의 설명)을 제공하는 것입니다. 이제 TS는 컴파일 타임에 함수를 올바르게 호출했는지 알아낼 수 있고 함수를 잘못 호출하면 오류를 줄 수 있습니다.

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