Generics tip parametreleridir. Generic bir fonksiyon, genellikle T olarak adlandırılan bir yer tutucu tip bildirir ve her çağrı onu doldurur; böylece giren tipler çıkan tipleri belirler. Tek bir fonksiyon sayılar, string'ler ve kendi nesneleriniz için çalışır ve her çağrı yine tamamen tiplidir.
Fonksiyon adından sonraki <T> tip parametresini bildirir. items: T[] onu girdi için, T | undefined ise çıktı için kullanır ve ikisini birbirine bağlar. number ya da string hiç yazmadınız: TypeScript T tipini argümandan çıkardı.
Neden any ya da unknown Değil?
Generics olmadan parametreyi any ya da unknown olarak tiplerdiniz. İkisi de her diziyi kabul eder ve ikisi de girdi ile çıktı arasındaki bağlantıyı kaybeder:
| Parametre tipi | Her girdiyi kabul eder mi | Sonuç tipi | Kontrol edilir mi |
|---|---|---|---|
any | evet | any | hayır: hatalar derlenir |
unknown | evet | unknown | evet, ama kullanmadan önce daraltmanız gerekir |
T (generic) | evet | girdiye bağlı | evet, kesin tiple |
Tip Argümanı Çıkarımı
TypeScript genellikle tip argümanlarını geçirdiğiniz değerlerden çıkarır. Bunları çağrıda açılı parantez içinde açıkça da yazabilirsiniz; argümanlarda T ile ilgili hiçbir şey yoksa ya da çıkarım istemediğiniz bir şeyi seçerse bu gereklidir.
İki çıkarım sonucunu bilmekte fayda var. Açık argüman olmadan pair(1, "one") bir hatadır: TypeScript ilk argümandan T = number çıkarır ve ardından Argument of type 'string' is not assignable to parameter of type 'number'. (TS2345) bildirir. Ve hiç argümanı olmayan emptyList(), T = unknown alır ve unknown[] verir; bu nadiren istediğiniz şeydir.
Birden Fazla Tip Parametresi
Bir fonksiyon, virgülle ayırarak ihtiyaç duyduğu kadar tip parametresi bildirebilir. Her biri bağımsız olarak çıkarılır.
mapValues üç şeyi aynı anda çıkarır: K değeri "tea" | "cake", V değeri number, R ise callback'in dönüşünden string olur. K extends string bir kısıtlamadır (constraint) ve bir sonraki sayfada anlatılır.
Generic Interface'ler ve Type Alias'lar
Tipler de parametre alabilir. O zaman tipi kullanırken argümanı yazarsınız: Box<number>, ApiResponse<User>. Yerleşik koleksiyon tiplerinin çoğu bu şekilde çalışır: Array<T>, Map<K, V>, Promise<T>, Record<K, V>.
Result<T, E = string> ayrıca bir varsayılan tip parametresi de gösteriyor: Result<number>, Result<number, string> anlamına gelir. Opsiyonel fonksiyon parametreleri gibi, varsayılanı olan parametreler zorunlu olanlardan sonra gelmelidir.
Generic Sınıflar
Bir sınıf, adından sonra tip parametreleri alır ve her örnek bunları sabitler. Alanlar, metotlar ve constructor parametreleri bunların hepsini kullanabilir.
Constructor bir T alıyorsa açık argümanı yazmayabilirsiniz: new Box(5), Box<number> olarak çıkarılır. Statik üyeler bir örneğe değil sınıfın kendisine aittir, bu yüzden sınıfın tip parametresini kullanamazlar (Static members cannot reference class type parameters., TS2302).
Generic Arrow Function'lar ve Fonksiyon Tipleri
Tip parametresi listesi parametre listesinin önüne gelir. Aynı sözdizimi generic bir fonksiyon tipini de tarif eder.
const last = <T>(items: T[]): T | undefined => items[items.length - 1];
type Mapper = <T, R>(items: T[], fn: (item: T) => R) => R[];
const mapAll: Mapper = (items, fn) => items.map(fn);
// In a .tsx file, <T> looks like a JSX tag. Add a trailing comma:
const lastTsx = <T,>(items: T[]) => items[items.length - 1];
const Tip Parametreleriyle Literal Tipleri Çıkarmak
Varsayılan olarak bir generic genişletilmiş tipler çıkarır: pair("a", "b") sonucu [string, string] olur. Tam değerler önemli olduğunda (route adları, event adları, sütun listeleri) parametreyi const olarak işaretleyin (TypeScript 5.0 ve sonrası); o zaman argüman as const ile yazılmış gibi çıkarım yapar:
Çağıran sıradan bir dizi yazar, fonksiyon ise literal tipleri korur.
Generics Ne Zaman Kullanılmamalı
Bir tip parametresi iki şeyi birbirine bağladığında yerini hak eder: bir parametre ile dönüş tipi, iki parametre ya da bir parametre ile bir callback. T yalnızca bir kez geçiyorsa hiçbir şey eklemez ve düz bir tip daha anlaşılırdır.
// Pointless: T is used once, so it is just a longer way to write unknown
function logValue<T>(value: T): void {
console.log(value);
}
// Clearer
function logValueSimple(value: unknown): void {
console.log(value);
}
// Also pointless: returns T but nothing connects T to an argument,
// so the caller is really just asserting a type
function parseJson<T>(text: string): T {
return JSON.parse(text);
}
Sonuncusu yaygındır ve yanıltıcıdır: parseJson<User>(text) tip güvenli görünür ama hiçbir şeyi kontrol etmez, tıpkı JSON.parse(text) as User gibi. Bunun yerine unknown döndürün ve doğrulayın. Aşırı kullanımın diğer işaretleri: her zaman aynı argümanı alan bir tip parametresi ya da bilinen iki tipin bir union'ı ile değiştirilebilecek bir tip parametresi.
T hakkında bir şey bilmesi gereken generics için (bir length özelliği olduğu ya da K değerinin T tipinin bir anahtarı olduğu gibi), sonraki adım extends ile yazılan kısıtlamalardır.
Sıkça Sorulan Sorular
TypeScript'te generics nedir?
Generics tip parametreleridir: bir fonksiyon, interface, type alias ya da sınıf her kullanıldığında gerçek bir tiple doldurulan T gibi yer tutuculardır. function first<T>(items: T[]): T | undefined her dizi için çalışır ve sonuç, geçirdiğiniz dizinin eleman tipine sahip olur; yani first([1, 2]) sonucu number | undefined, first(["a"]) sonucu ise string | undefined olur.
Generics ile any arasındaki fark nedir?
any tip kontrolünü kapatır: giren değerle çıkan değer arasında hiçbir ilişki kalmaz ve sonuç da any olur. Bir generic ise bu ilişkiyi korur: identity<T>(x: T): T tam olarak geçirdiğiniz tipi döndürür. Her şeyi kabul ediyor ama tipi geri vermeniz gerekmiyorsa unknown, gerekiyorsa bir generic kullanın.
TypeScript'te <T> ne anlama gelir?
T adında bir tip parametresi bildirir. function wrap<T>(value: T) içinde T, TypeScript'in her çağrıda argümandan doldurduğu ya da sizin wrap<string>("a") gibi açıkça geçirdiğiniz bir tip değişkenidir. T adı yalnızca bir gelenektir; TItem veya Key gibi daha uzun adlar da aynı şekilde çalışır.
TypeScript'te generic bir arrow function nasıl yazılır?
Tip parametresi listesini parametrelerin önüne koyun: const first = <T>(items: T[]): T | undefined => items[0];. Bir .tsx dosyasında <T> bir JSX etiketi olarak okunur; bu yüzden sonda virgülle <T,> ya da <T extends unknown> yazın.
TypeScript'te bir generic için varsayılan tip nasıl belirlenir?
Parametreden sonra = Type ekleyin: interface ApiResponse<T = unknown> { data: T }. Böylece argümansız ApiResponse, ApiResponse<unknown> anlamına gelir. Varsayılan değeri olan parametreler, opsiyonel fonksiyon parametreleri gibi, varsayılanı olmayanlardan sonra gelmelidir.