Menu

TypeScript Function Overloading: Overload İmzaları

TypeScript function overload'ları, bir fonksiyonun her biri kendi dönüş tipine sahip birkaç çağrı imzasına sahip olmasını sağlar. Overload imzaları artı gerçekleme kalıbını, derleyicinin kontrol ettiği kuralları, bir union parametrenin ne zaman daha iyi olduğunu ve sınıflardaki overload'ları öğrenin.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

TypeScript'te function overloading, bir fonksiyon için birkaç çağrı imzası ve ardından tek bir gerçekleme yazmak demektir. Her imza farklı parametre tiplerini farklı bir dönüş tipiyle eşleştirebilir ve çağıran kesin olanı alır.

Overload'lar olmasaydı parse her çağrı için number | number[] döndürürdü ve siz sonucu kendiniz daraltana kadar one + 1 bir hata olurdu.

Overload İmzaları ve Gerçekleme

Overload edilmiş bir fonksiyonun iki kısmı vardır:

  1. Overload imzaları: desteklenen her çağrı biçimi için bir tane olmak üzere gövdesiz bildirimler. Çağıranların kullanabildiği tek imzalar bunlardır.
  2. Gerçekleme imzası (implementation signature): gövdesiyle birlikte son bildirim. Parametreleri overload'ların kabul ettiği her şeyi kabul etmeli, dönüş tipi de her overload'ın dönüş tipini kapsamalıdır. Dışarıdan görünmez.

Tipler yalnızca derleme zamanında vardır, bu yüzden çalışma zamanında tek bir JavaScript fonksiyonu bulunur. Gerçekleme ne yapacağına karar vermek için argümanlarını incelemek zorundadır (typeof, Array.isArray, arguments.length...). Derleyici overload'ların ve gerçeklemenin uyuştuğunu kontrol eder:

function format(value: string): string;
function format(value: number): number {
  return value;
}
// error TS2394: This overload signature is not compatible with its implementation signature.

Çözüm gerçeklemeyi genişletmektir: function format(value: string | number): string | number.

Gerçekleme İmzası Çağrılamaz

İnsanları en çok şaşırtan kural budur. Bir çağrı, overload imzalarından biriyle tek başına eşleşmelidir; TypeScript onları birleştirmez.

Derleyici şunu yazdırır:

index.ts(12,19): error TS2769: No overload matches this call.
  The last overload gave the following error.
    Argument of type 'string | string[]' is not assignable to parameter of type 'string[]'.
      Type 'string' is not assignable to type 'string[]'.

Gerçekleme string | string[] kabul eder, ama çağıranlar onu göremez. Union'ı alıp union döndüren üçüncü bir overload ekleyin, çağrı derlenir ve [ 1, 2 ] yazdırır:

function parse(input: string): number;
function parse(input: string[]): number[];
function parse(input: string | string[]): number | number[];
function parse(input: string | string[]): number | number[] {
  return Array.isArray(input) ? input.map(Number) : Number(input);
}

Farklı Sayıda Parametreler

Overload'lar farklı sayıda argüman içeren çağrıları da tanımlar. Burada bir tarih bir zaman damgasından ya da yıl, ay ve günden oluşturulabilir, ama iki sayıdan oluşturulamaz:

İki opsiyonel parametreli tek bir imza makeDate(2024, 3) çağrısını kabul eder ve sessizce yanlış tarihi oluştururdu. Overload'lar bunu bir derleme hatasına (TS2575) dönüştürür.

Sıra Önemlidir

TypeScript overload'ları yukarıdan aşağıya dener ve eşleşen ilkini seçer. En özel imzaları başa koyun. Listenin başındaki geniş bir overload, sonrakiler için yazılmış çağrıları yutar:

function describe(value: unknown): string;   // matches everything
function describe(value: string): "text";    // never chosen
function describe(value: unknown): string {
  return typeof value === "string" ? "text" : "other";
}

const d = describe("hi"); // d: string, not "text"

İlk iki imzanın yerini değiştirin, describe("hi") çağrısı "text" olarak tiplenir.

Overload mu, Union Parametre mi?

Overload'lar, dönüş tipi argüman tiplerine bağlı olduğunda fazladan satırlarına değer. Bağlı olmadığında union parametreli tek bir imza daha kısa ve okunaklıdır, üstelik overload'ların reddedeceği union argümanlarını da kabul eder.

KullanınNe zaman
Bir union parametreHer girdi için aynı dönüş tipi
Opsiyonel parametrelerÇağrı biçimleri yalnızca serbestçe atlanabilen sondaki argümanlarla ayrılıyorsa
Overload'larDönüş tipi argümanlarla değişiyorsa ya da bazı argüman kombinasyonlarının reddedilmesi gerekiyorsa
Bir genericDönüş tipi argüman tipinden oluşturuluyorsa, örneğin identity<T>(x: T): T

Bir conditional tip ile birlikte bir generic, bazı overload kümelerini tek bir imza olarak ifade edebilir; ama iki üç durum için overload'ların okunması genellikle daha kolaydır.

Overload Edilmiş Metotlar ve Constructor'lar

Metotlar bir sınıfın içinde aynı kalıbı kullanır: overload imzaları, ardından gövdesi olan metot. Constructor'lar da aynı şekilde overload edilebilir.

Interface'ler ve nesne tipleri de, birkaç call signature ya da aynı adı taşıyan birkaç metot imzası olarak overload bildirebilir. Pek çok yerleşik fonksiyon bu şekilde bildirilmiştir: bir editörde bir dizi üzerindeki reduce metodunun üzerine gelin, "+2 overloads" gösterir.

Sıkça Sorulan Sorular

TypeScript function overloading destekler mi?

Evet, tip düzeyinde. Birkaç overload imzası (gövdesiz bildirimler) ve ardından tek bir gerçekleme yazarsınız. Çağıranlar yalnızca overload imzalarını görür. Çalışma zamanında yine tek bir JavaScript fonksiyonu vardır, bu yüzden gerçekleme argümanları kendisi kontrol eder ve her durumu ele alır.

"No overload matches this call" ne anlama gelir?

TS2769 hatası: argümanlar overload imzalarının hiçbirine uymuyor. Gerçekleme imzası sayılmaz, bu yüzden gerçekleme kabul etse bile string | string[] gibi bir union argümanıyla yapılan bir çağrı başarısız olur. Union'ı alan bir overload ekleyin ya da overload'ları tek bir imzayla değiştirin.

Union tip yerine ne zaman overload kullanmalıyım?

Dönüş tipi hangi argüman tiplerinin verildiğine bağlı olduğunda overload kullanın; örneğin içeri string girince dışarı number, ama içeri string[] girince dışarı number[] çıkıyorsa. Dönüş tipi her girdi için aynıysa union parametreli tek bir imza daha basittir ve union argümanlarını da kabul eder.

TypeScript'te arrow function'lar overload edilebilir mi?

Overload bildirim sözdizimiyle olmaz; bu yalnızca function bildirimleri ve metotlarla çalışır. Bir değişkene birkaç call signature içeren overload'lu bir tip verebilirsiniz, type Parse = { (s: string): number; (s: string[]): number[] }, ama ona bir arrow function atamak genellikle bir type assertion gerektirir; bu yüzden bir function bildirimi daha temiz bir seçimdir.

Overload imzam neden gerçekleme imzasıyla uyumlu değil?

TS2394 hatası, bir overload'ın gerçeklemenin kabul etmediği ya da döndürmediği bir şeyi kabul ettiği veya döndürdüğü anlamına gelir. Gerçeklemenin parametreleri her overload'ın parametrelerini kabul etmeli, dönüş tipi de her overload'ın dönüş tipiyle uyumlu olmalıdır. Gerçeklemeyi genişletmek (çoğu zaman bir union'a) bunu düzeltir.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA