TypeScript'te yöntem aşırı yüklemesi yapmanın bir yolu var mı?


109

TypeScript dilinde yöntem aşırı yüklemesi yapmanın bir yolu var mı?

Bunun gibi bir şey başarmak istiyorum:

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

İşte yapmak istemediğim şeylere bir örnek (JS'de hack'in aşırı yüklenmesinin bu kısmından gerçekten nefret ediyorum):

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
Evet, bir şans var, dil henüz ölmemiş. Başka soru?
hakre

6
@hakre TypeScript'in zaten yöntem aşırı yüklemesini desteklediğini düşünürsek, bunu söylemek garip bir şey.
svick

@svick: peki, bu yönteme aşırı yükleme mi diyorsunuz? Cevabınızda, yöntemin kendisi aşırı yüklenmemiş, tek vücut etrafta dolanıyor.
hakre

2
@hakre Spesifikasyon, buna yöntem aşırı yükleme olarak adlandırılır. Kesinlikle bunun özellikle hoş bir versiyonu olmadığını iddia edebilirsiniz, ama bence hiç var olmadığını söyleyemezsiniz.
svick

@svick: Ben de söylemedim. Ama bana göre OP'nin sorduğu şans, yöntem aşırı yüklemesinin zihinsel modeli hakkında belirli. Saç kırma için, yöntem imzası aşırı yükleme olduğunu söyleyebiliriz;)
hakre

Yanıtlar:


165

Spesifikasyona göre, TypeScript, yöntem aşırı yüklemesini desteklemektedir, ancak oldukça gariptir ve çok sayıda manuel çalışma kontrol tipi parametre içerir. Bunun çoğunlukla, düz JavaScript'te yöntem aşırı yüklemesine en yakın olanın, denetlemeyi de içermesi ve TypeScript'in gereksiz çalışma zamanı performans maliyetlerinden kaçınmak için gerçek yöntem gövdelerini değiştirmemeye çalışması nedeniyle olduğunu düşünüyorum.

Doğru anladıysam, önce her aşırı yükleme için bir yöntem bildirimi yazmalı ve ardından hangi aşırı yüklemenin çağrıldığına karar vermek için bağımsız değişkenlerini kontrol eden bir yöntem uygulaması yazmalısınız . Uygulamanın imzası tüm aşırı yüklerle uyumlu olmalıdır.

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, yöntem aşırı yüklemesini hiç desteklemiyor, değil mi? Öyleyse JS'ye geri dönmek nasıl yardımcı olacak?
svick

Arayüzleri kontrol etmeye ne dersiniz? Bundan daha iyi bir çözümünüz var mı: stackoverflow.com/questions/14425568/… ?
DiPix

hmm .. Bunu gerçekten sevmiyorum, bunun yerine isteğe bağlı bir parametrenin olması okumak daha iyi.
LuckyLikey

3
Bence burada önemli olan, kodunuzu bir ton yazım ifadesinden kontrol etmeden okunabilir tutmasıdır. Neye karıştığı kimin umurunda.
Brain2000

34

Netlik için güncelleme. TypeScript'te yöntem aşırı yüklemesi, temsil edilmesi gereken bir API ile mevcut kitaplıklar için tür tanımları oluşturmanıza izin verdiği ölçüde yararlı bir özelliktir.

Bununla birlikte, kendi kodunuzu yazarken, isteğe bağlı veya varsayılan parametreleri kullanarak bilişsel aşırı yükten kaçınabilirsiniz. Bu, yöntem aşırı yüklemelerine karşı daha okunaklı bir alternatiftir ve aynı zamanda sezgisel olmayan sıralamayla aşırı yükler oluşturmaktan kaçınacağınız için API'nizi dürüst tutar.

TypeScript aşırı yüklemelerinin genel kanunu şöyledir:

Aşırı yük imzalarını silebilirseniz ve tüm testleriniz başarılı olursa, TypeScript aşırı yüklemelerine ihtiyacınız yoktur.

Genellikle aynı şeyi isteğe bağlı veya varsayılan parametrelerle - veya birleşim türleriyle veya biraz nesne yönelimi ile elde edebilirsiniz.

Gerçek Soru

Asıl soru şunların aşırı yüklenmesini ister:

someMethod(stringParameter: string): void {

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

Şimdi, ayrı uygulamalarla aşırı yüklemeleri destekleyen dillerde bile (not: TypeScript aşırı yüklemeleri tek bir uygulamayı paylaşır) - programcılar, siparişte tutarlılık sağlamaya yönelik tavsiyelerdir. Bu, imzaları:

someMethod(stringParameter: string): void {

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

Her stringParameterzaman gereklidir, bu yüzden önce gider. Bunu çalışan bir TypeScript aşırı yüklemesi olarak yazabilirsiniz:

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

Ancak TypeScript aşırı yük yasasını takip ederek aşırı yük imzalarını silebiliriz ve tüm testlerimiz yine de geçecektir.

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

Asıl Soru, Gerçek Sırayla

Orijinal siparişte ısrar etmeye kararlı olsaydınız, aşırı yüklemeler şöyle olurdu:

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

Şimdi, parametreleri nereye koyacağınızı bulmak için çok fazla dallanma var, ancak bu kadarını okuyorsanız, bu sırayı gerçekten korumak istediniz ... ama bekleyin, TypeScript aşırı yüklemeleri yasasını uygularsak ne olur?

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

Zaten Yeterince Dallanma

Elbette, yapmamız gereken tür kontrolünün miktarı göz önüne alındığında ... belki de en iyi cevap basitçe iki yönteme sahip olmaktır:

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

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

bu genellikle yöntem aşırı yükleme olarak bilinmez. sorusuna da bakın, ilk parametrenin türü değişir.
hakre

3
Cevabımda - isteğe bağlı parametreyi en sona koyacağınızı, böylece numberparametrenin ikinci bağımsız değişken olacağını ve isteğe bağlı olacağını kabul ettim . TypeScript, "uygun" yöntem aşırı yüklemelerini desteklemez - ancak C # dünyası bile aşırı yüklemelerden, birçok durumda daha okunabilir koda yol açtığı için isteğe bağlı parametrelere doğru kaymaktadır.
Fenton

Yani if (typeof numberParameter != 'undefined'), doğru;)
Juan Mendes

Bu, kullanım durumunuza, özellikle de sıfırları kabul edip etmediğinize bağlıdır. Yapmanız gerekiyorsa, !==hokkabazlıktan kaçınmak için kullanmayı unutmayın .
Fenton

1
@Sebastian, bağımlılık enjeksiyonu için bir fırsat gibi görünüyor. TypeScript'te yöntem aşırı yüklemesinin birden çok dekorasyon, varsayılan parametre ve birleşim türlerine sahip tek bir yöntemi içerdiği göz önüne alındığında, daha iyi bir deneyim sağlar. Yöntemler daha önemli şekillerde farklılık gösteriyorsa, ya bir soyutlama kullanırsınız ya da birden çok yöntem uygularsınız.
Fenton

7

Keşke. Bu özelliği de istiyorum, ancak TypeScript'in aşırı yüklenmiş yöntemleri olmayan türlenmemiş JavaScript ile birlikte çalışabilir olması gerekiyor. Örneğin, aşırı yüklenmiş yönteminiz JavaScript'ten çağrıldıysa, yalnızca bir yöntem uygulamasına gönderilebilir.

Codeplex ile ilgili birkaç tartışma var. Örneğin

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

Hala TypeScript'in tüm if'ing ve switch'leri oluşturması gerektiğini düşünüyorum, böylece yapmamız gerekmeyecek.


2

Neden fonksiyon bağımsız değişkeni olarak isteğe bağlı özellik tanımlı arabirimi kullanmayalım ..

Bu sorudaki durum için, bazı isteğe bağlı özelliklerle tanımlanmış bir satır içi arabirim kullanmak yalnızca aşağıdaki gibi doğrudan kod yapabilir:

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'te sağlanan aşırı yükleme, diğerlerinin yorumlarında belirtildiği gibi, diğer statik diller gibi karşılık gelen uygulama kodlarını desteklemeden yalnızca işlevin farklı imzalarının bir listesidir. Dolayısıyla, uygulamanın hala tek bir işlev gövdesinde yapılması gerekmekte, bu da Typescript'te işlev aşırı yüklemesinin kullanımını gerçek aşırı yükleme özelliğini destekleyen diller kadar rahat olmamaktadır.

Bununla birlikte, anonim bir arayüzde isteğe bağlı özellik desteğinin, eski fonksiyon aşırı yüklemesinden rahat bölgeyi karşılamak için böyle bir yaklaşım olduğu eski programlama dilinde mevcut olmayan birçok yeni ve kullanışlı malzeme hala bulunmaktadır.


0

Çok fazla yöntem aşırı yüklemesi varyasyonu varsa, başka bir yol da içinde tüm bağımsız değişkenleriniz olan bir sınıf oluşturmaktır. Böylece sadece istediğiniz parametreyi herhangi bir sırada geçirebilirsiniz.

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

Ayrıca varsayılan değerlere sahip bir kurucu oluşturabilir ve / veya bazı zorunlu argümanlar iletebilirsiniz. O zaman şu şekilde kullanın:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.