TypeScript işlevi aşırı yüklenmesi


244

TypeScript dil spesifikasyonunun 6.3 bölümü, fonksiyon aşırı yüklemesi hakkında konuşuyor ve bunun nasıl uygulanacağı konusunda somut örnekler veriyor. Ancak böyle bir şey denerseniz:

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

}

İşlev parametreleri farklı türlerde olsa bile yinelenen tanımlayıcı belirten bir derleyici hatası alıyorum. İkinci createFeatureLayer işlevine ek bir parametre eklesem bile, derleyici hatası alıyorum. Fikirler, lütfen.


Yanıtlar:


189

Bunun nedeni, her iki işlev de JavaScript'e derlendiğinde imzalarının tamamen aynı olması olabilir. JavaScript'in türü olmadığından, aynı sayıda argüman alan iki işlev oluşturuyoruz. Bu nedenle, TypeScript bu tür işlevleri yaratmamızı kısıtlıyor.

TypeScript, parametre sayısına göre aşırı yüklemeyi destekler, ancak OO dilleriyle karşılaştırıldığında izlenecek adımlar biraz farklıdır. Başka bir SO sorusuna yanıt olarak, birisi güzel bir örnekle açıkladı: Yöntem aşırı yükleme? .

Temel olarak, yaptığımız şey, TypeScript'in derleme hataları vermemesi için sadece bir işlev ve bir dizi bildirim oluşturuyoruz. Bu kod JavaScript'e derlendiğinde, yalnızca somut işlev görünür. Bir JavaScript işlevi birden çok argüman iletilerek çağrılabilir, sadece çalışır.


50
Dil, bunu destekleyecek şekilde değiştirilebilir. Teoride, derlenmiş TypeScript tarafından adlandırılan ve çağrılan işlev uygulamaları üretilebilir (örn. CreateFeatureLayer_1 ve createFeatureLayer_2) ve createFeatureLayer, vanilya JavaScript ile birlikte çalışma argümanlarının içeriğine dayanarak hangisinin çağrılacağını belirleyebilir.
Thomas S. Trias

8
TypeScript'te aşırı yükleme sadece parametre sayısına bağlı olarak mümkünyken, Steve Fenton'un cevabında gösterildiği gibi türe dayalı aşırı yükleme de mümkündür.
Matthijs Wessels

9
Bu biraz topal; TypeScript gerçekten, benzersiz bir şekilde adlandırılmış uygulamayı, aktarılana göre uygun şekilde seçen "meta işlevi" oluşturuyor olmalıdır. Şimdi nasıl olduğu derleyiciyi geçebileceğiniz bir yarık var ama tip koklama uygulamanız yanlış olabilir.
Ezekiel Victor

5
@EzekielVictor TypeScript, çalışma zamanında türleri denetlemenin güvenilir bir yolu olsaydı bunu yapardı.
thorn̈

3
Bu daha da karmaşıktır, JavaScript'in türleri ile yapılabilir, ancak arayüzler type, sler, numaralar, jenerikler vb.Gibi TS'ye özgü kavramlar çalışma zamanında kaybolur. Bu yüzden yapamazsın someObject instanceof ISomeInterfaceDefinedInTypeScript.
Morgan Touverey Quilling

209

TypeScript'e aşırı yüklediğinizde, yalnızca birden fazla imza içeren bir uygulamanız olur.

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

Yalnızca üç aşırı yükleme, TypeScript tarafından bir yöntem çağrısı için olası imzalar olarak tanınır, gerçek uygulama tarafından tanınmaz.

Sizin durumunuzda, parametrelerde yeterince ortaklık olmadığından, yöntem gövdesinin ne yapacağına karar vermek için çok sayıda "ifs" e sahip olması muhtemel olmasını sağladığından, kişisel olarak farklı adlara sahip iki yöntem kullanacağım.

TypeScript 1.4

TypeScript 1.4'ten itibaren, bir rakor tipini kullanarak aşırı yükleme ihtiyacını ortadan kaldırabilirsiniz. Yukarıdaki örnek kullanılarak daha iyi ifade edilebilir:

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

Türü a"ya stringya number" dır .


Mükemmel cevap. Sadece vurgulamak istiyorum, bu gibi nedenlerle aşırı yüklenmeye çalışırken bu yararlı olmayabilir: Ben bir örnek istiyorum, nerede aynı yapıcı kullanarak, beklenen tüm özellikleri tanımlayan bir nesneyi geçebilir ve bir örnek, bireysel parametreleri class Foo { constructor(obj) { } constructor (a: number, b: string, c: boolean) {} }
geçirin

Orada eğer arama şube gerek var - Genel olarak, ben daha çok Nesneyi bana her yol oluşturmak için bir fabrika yöntemini kullanmayı tercih ediyorum Foo.fromObject(obj)ve Foo.fromJson(str)vb.
Fenton

Ancak bu, parametrelerini her zaman bir nesne veya tek bir dize olarak geçireceğini varsayar; önceki yorumumdan da vurgulandığı gibi ayrı ayrı geçmelerini isterseniz ne olur? Foo.methos(1, 2, 3) Foo.method(1) Foo.method(Obj) Ayrıca FooSınıfta farklı yöntemler olduğunu fark ettim , fromObject ve fromJson?
Hlawuleka MAS

1
Bu farkı kaynağa geri takip ederseniz, genellikle buna gerek olmadığını görürsünüz. Örneğin, yazmanız myNumya da myObjyine de yapmanız gerekir , bu yüzden neden ayrı yöntemlere sahip olmuyorsunuz ve gereksiz dallanma mantığından her şeyi netleştirin / kaçının.
Fenton

2
Parametrelere bağlı olarak farklı dönüş türlerine sahip olmak istiyorsanız, bir birleşim türü kullanmanın sorunlu olabileceğini unutmayın. Dönüş türü her zaman parametre türlerinden biriyle eşleşiyorsa, jenerikler ile çözülebilir, ancak diğer durumlarda aşırı yükler en iyi çözümdür.
John Montgomery

45

Sen edebilirsiniz beyan birden çağırma imzaları olan bir tür sahip olarak işlevini ilan ederek aşırı yüklenmiş bir işlevi:

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

Sonra aşağıdakiler:

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

İşlevin gerçek tanımı tekil olmalı ve bağımsız değişkenler üzerinde uygun gönderimi gerçekleştirmelidir.

Örneğin, bir sınıf kullanmak (uygulayabilen IFooancak uygulamak zorunda olmayan):

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

Burada ilginç olan, anyformun daha özel olarak yazılmış geçersiz kılmalar tarafından gizlenmiş olmasıdır .

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

Genel olarak aşırı fonksiyon yüklemesi nedir?

Fonksiyon aşırı yükleme veya metot aşırı yükleme yaratma yeteneği olan birden fazla işlevi içinde aynı adı ile farklı uygulamaları ( Vikipedi )


JS'de aşırı işlev yüklemesi nedir?

Bu özellik JS'de mümkün değildir - birden fazla bildirim olması durumunda en son tanımlanan işlev alınır:

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

... ve TS'de mi?

Aşırı yükler , JS çalışma zamanı üzerinde etkisi olmayan bir derleme zamanı yapısıdır:

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

Yukarıdaki kodu (JS'den daha güvenli) kullanırsanız, yinelenen bir uygulama hatası tetiklenir. TS, ilk montaj aşırı yükünü yukarıdan aşağıya sıraya göre seçer, böylece aşırı yükler en spesifikinden en genişine doğru sıralanır.


TS'de yöntem aşırı yüklenmesi: daha karmaşık bir örnek

Aşırı yüklenmiş sınıf yöntemi türleri, aşırı yük işlevine benzer şekilde kullanılabilir:

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

İşlev uygulaması derleyici tarafından uygulanan tüm aşırı yük imzalarıyla uyumlu olduğu için çok farklı aşırı yüklemeler mümkündür.

Daha fazla bilgi:


0

Başkalarına kafa gibi, en azından AnPlay 2 için WebPack tarafından derlenen TypeScript tarafından tezahür ettiği gibi, overLOADED yöntemleri yerine sessizce overWRITTEN aldığını gözlemledim.

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

Arayan:

myComponent.method()

yöntemi, argümansız bir şekilde, yok argümanı yoksayılarak, çıktı ile yöntemi yürütüyor gibi görünüyor:

with arg

2
Aşırı yükleriniz için ayrı gövdeler ilan edemezsiniz, sadece farklı imzalar.
adharris

5
Hangi TypeScript derleyicisinin hangi sürümünü kullandığınızdan emin değilim, ancak geçerli sürüm Duplicate function implementationböyle bir kod için uyarı veriyor.
Royston Shufflebotham

0

Daktiloda fonksiyon aşırı yüklenmesi:

Wikipedia'ya göre (ve birçok programlama kitabında) yöntem / işlev aşırı yüklemesinin tanımı şöyledir:

Bazı programlama dillerinde, işlev aşırı yüklemesi veya yöntem aşırı yüklemesi, farklı uygulamalarla aynı adda birden çok işlev oluşturma yeteneğidir . Aşırı yüklenmiş bir işleve yapılan çağrılar, bu işlevin çağrı bağlamına uygun belirli bir uygulamasını çalıştırarak bir işlev çağrısının bağlama bağlı olarak farklı görevler gerçekleştirmesine izin verir.

Daktilo yazısında, argümanların sayısına ve türüne göre çağrılan aynı işlevin farklı uygulamalarına sahip olamayız. Bunun nedeni, TS JS'ye derlendiğinde, JS'deki işlevlerin aşağıdaki özelliklere sahip olmasıdır:

  • JavaScript işlev tanımları parametreleri için veri türleri belirtmez
  • JavaScript işlevleri çağrıldığında argüman sayısını kontrol etmez

Bu nedenle, sıkı bir anlamda, TS işlev aşırı yüklemesinin mevcut olmadığı iddia edilebilir. Bununla birlikte, TS kodunuzda fonksiyon aşırı yüklemesini mükemmel bir şekilde taklit edebilecek şeyler vardır.

İşte bir örnek:

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 dokümanları bu yöntemin aşırı yüklenmesi olarak adlandırır ve temel olarak yaptığımız şey TS derleyicisine çok sayıda yöntem imzası (olası parametrelerin ve türlerin açıklamaları) sağlamaktır. Şimdi TS derleme zamanı boyunca fonksiyonumuzu doğru çağırıp çağırmamamızı anlayabilir ve fonksiyonu yanlış çağırdığımızda bize bir hata verebilir.

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.