Türkçe

Gelişmiş TypeScript jeneriklerini inceleyin: kısıtlamalar, yardımcı tipler, tip çıkarımı ve küresel bağlamda sağlam, yeniden kullanılabilir kodlar için pratik uygulamalar.

TypeScript Jenerikleri: Gelişmiş Kullanım Desenleri

TypeScript jenerikleri, daha esnek, yeniden kullanılabilir ve tip güvenli kod yazmanıza olanak tanıyan güçlü bir özelliktir. Derleme zamanında tip kontrolünü sürdürürken, çeşitli diğer tiplerle çalışabilen tipler tanımlamanızı sağlarlar. Bu blog yazısı, coğrafi konumları veya geçmişleri ne olursa olsun her seviyedeki geliştiriciler için pratik örnekler ve içgörüler sunarak gelişmiş kullanım desenlerine derinlemesine bir bakış sunmaktadır.

Temelleri Anlamak: Kısa Bir Tekrar

Gelişmiş konulara dalmadan önce, temelleri hızlıca tekrar edelim. Jenerikler, tek bir tiple değil, çeşitli tiplerle çalışabilen bileşenler oluşturmanıza olanak tanır. Fonksiyon veya sınıf adından sonra açılı parantezler (`<>`) içinde jenerik bir tip parametresi bildirirsiniz. Bu parametre, fonksiyon veya sınıf kullanıldığında daha sonra belirtilecek olan gerçek tip için bir yer tutucu görevi görür.

Örneğin, basit bir jenerik fonksiyon şöyle görünebilir:

function identity(arg: T): T {
  return arg;
}

Bu örnekte, T jenerik tip parametresidir. identity fonksiyonu, T tipinde bir argüman alır ve T tipinde bir değer döndürür. Bu fonksiyonu daha sonra farklı tiplerle çağırabilirsiniz:


let stringResult: string = identity("hello");
let numberResult: number = identity(42);

Gelişmiş Jenerikler: Temellerin Ötesinde

Şimdi, jeneriklerden yararlanmanın daha sofistike yollarını keşfedelim.

1. Jenerik Tip Kısıtlamaları

Tip kısıtlamaları, jenerik bir tip parametresiyle kullanılabilecek tipleri sınırlamanıza olanak tanır. Bu, jenerik bir tipin belirli özelliklere veya metotlara sahip olduğundan emin olmanız gerektiğinde çok önemlidir. Bir kısıtlama belirtmek için extends anahtar kelimesini kullanabilirsiniz.

Bir fonksiyonun length özelliğine erişmesini istediğiniz bir örneği düşünün:

function loggingIdentity(arg: T): T {
  console.log(arg.length);
  return arg;
}

Bu örnekte, T, number tipinde bir length özelliğine sahip olan tiplerle sınırlandırılmıştır. Bu, arg.length'e güvenli bir şekilde erişmemizi sağlar. Bu kısıtlamayı karşılamayan bir tip geçmeye çalışmak, derleme zamanı hatasına neden olur.

Küresel Uygulama: Bu, özellikle diziler veya stringler gibi uzunluklarını sıkça bilmeniz gereken verilerle çalışırken veri işleme senaryolarında kullanışlıdır. Bu desen, Tokyo, Londra veya Rio de Janeiro'da olmanızdan bağımsız olarak aynı şekilde çalışır.

2. Arayüzlerle Jenerik Kullanımı

Jenerikler, arayüzlerle (interfaces) sorunsuz bir şekilde çalışarak esnek ve yeniden kullanılabilir arayüz tanımları oluşturmanıza olanak tanır.

interface GenericIdentityFn {
  (arg: T): T;
}

function identity(arg: T): T {
  return arg;
}

let myIdentity: GenericIdentityFn = identity;

Burada, GenericIdentityFn, jenerik bir T tipi alan ve aynı T tipini döndüren bir fonksiyonu tanımlayan bir arayüzdür. Bu, tip güvenliğini korurken farklı tip imzalarına sahip fonksiyonlar tanımlamanıza olanak tanır.

Küresel Perspektif: Bu desen, farklı türdeki nesneler için yeniden kullanılabilir arayüzler oluşturmanıza olanak tanır. Örneğin, farklı API'lerde kullanılan veri aktarım nesneleri (DTO'lar) için jenerik bir arayüz oluşturabilir ve uygulamanızın dağıtıldığı bölgeden bağımsız olarak tutarlı veri yapıları sağlayabilirsiniz.

3. Jenerik Sınıflar

Sınıflar (classes) da jenerik olabilir:


class GenericNumber {
  zeroValue: T;
  add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };

Bu GenericNumber sınıfı, T tipinde bir değer tutabilir ve T tipinde çalışan bir add metodu tanımlayabilir. Sınıfı istediğiniz tiple örneklersiniz. Bu, yığın (stack) veya kuyruk (queue) gibi veri yapıları oluşturmak için çok yardımcı olabilir.

Küresel Uygulama: Çeşitli para birimlerini (örneğin, USD, EUR, JPY) depolaması ve işlemesi gereken bir finansal uygulama düşünün. T'nin para birimi tipini temsil ettiği bir CurrencyAmount sınıfı oluşturmak için jenerik bir sınıf kullanabilir, böylece farklı para birimi miktarlarının tip güvenli hesaplamalarına ve depolanmasına olanak tanıyabilirsiniz.

4. Çoklu Tip Parametreleri

Jenerikler birden fazla tip parametresi kullanabilir:


function swap(a: T, b: U): [U, T] {
  return [b, a];
}

let result = swap("hello", 42);
// result[0] number, result[1] string

swap fonksiyonu, farklı tiplerde iki argüman alır ve tipleri değiştirilmiş bir demet (tuple) döndürür.

Küresel Alaka: Uluslararası iş uygulamalarında, müşteri ID'si (string) ve sipariş değeri (number) gibi farklı tiplerde iki ilgili veri parçasını alan ve bunları bir demet olarak döndüren bir fonksiyonunuz olabilir. Bu desen, herhangi bir ülkeyi kayırmaz ve küresel ihtiyaçlara mükemmel bir şekilde uyum sağlar.

5. Jenerik Kısıtlamalarda Tip Parametrelerini Kullanma

Bir kısıtlama içinde bir tip parametresi kullanabilirsiniz.


function getProperty(obj: T, key: K) {
  return obj[key];
}

let obj = { a: 1, b: 2, c: 3 };

let value = getProperty(obj, "a"); // value number tipindedir

Bu örnekte, K extends keyof T, K'nın yalnızca T tipinin bir anahtarı olabileceği anlamına gelir. Bu, nesne özelliklerine dinamik olarak erişirken güçlü bir tip güvenliği sağlar.

Küresel Uygulanabilirlik: Bu, özellikle özellik erişiminin geliştirme sırasında doğrulanması gereken yapılandırma nesneleri veya veri yapılarıyla çalışırken kullanışlıdır. Bu teknik, herhangi bir ülkedeki uygulamalarda uygulanabilir.

6. Jenerik Yardımcı Tipler

TypeScript, yaygın tip dönüşümlerini gerçekleştirmek için jenerikleri kullanan birkaç yerleşik yardımcı tip (utility types) sunar. Bunlar şunları içerir:

Örneğin:


interface User {
  id: number;
  name: string;
  email: string;
}

// Partial - tüm özellikler isteğe bağlı
let optionalUser: Partial = {};

// Pick - sadece id ve name özellikleri
let userSummary: Pick = { id: 1, name: 'John' };

Küresel Kullanım Durumu: Bu yardımcı programlar, API istek ve yanıt modelleri oluştururken paha biçilmezdir. Örneğin, küresel bir e-ticaret uygulamasında, Partial bir güncelleme isteğini (sadece bazı ürün detaylarının gönderildiği) temsil etmek için kullanılabilirken, Readonly ön yüzde görüntülenen bir ürünü temsil edebilir.

7. Jeneriklerle Tip Çıkarımı

TypeScript, jenerik bir fonksiyona veya sınıfa geçtiğiniz argümanlara dayanarak tip parametrelerini sıklıkla çıkarabilir. Bu, kodunuzu daha temiz ve okunması daha kolay hale getirebilir.


function createPair(a: T, b: T): [T, T] {
  return [a, b];
}

let pair = createPair("hello", "world"); // TypeScript, T'nin string olduğunu çıkarır

Bu durumda, TypeScript her iki argüman da string olduğu için T'nin otomatik olarak string olduğunu çıkarır.

Küresel Etki: Tip çıkarımı, açık tip ek açıklamalarına olan ihtiyacı azaltır, bu da kodunuzu daha öz ve okunabilir hale getirebilir. Bu, farklı deneyim seviyelerinin bulunabileceği çeşitli geliştirme ekipleri arasındaki işbirliğini geliştirir.

8. Jeneriklerle Koşullu Tipler

Koşullu tipler, jeneriklerle birlikte, diğer tiplerin değerlerine bağlı olan tipler oluşturmak için güçlü bir yol sağlar.


type Check = T extends string ? string : number;

let result1: Check = "hello"; // string
let result2: Check = 42; // number

Bu örnekte, Check, T string'i genişletiyorsa string olarak, aksi takdirde number olarak değerlendirilir.

Küresel Bağlam: Koşullu tipler, belirli koşullara göre tipleri dinamik olarak şekillendirmek için son derece kullanışlıdır. Verileri bölgeye göre işleyen bir sistem düşünün. Koşullu tipler daha sonra bölgeye özgü veri formatlarına veya veri tiplerine göre verileri dönüştürmek için kullanılabilir. Bu, küresel veri yönetişimi gereksinimleri olan uygulamalar için çok önemlidir.

9. Jeneriklerle Eşlenmiş Tipler Kullanımı

Eşlenmiş tipler (mapped types), bir tipin özelliklerini başka bir tipe göre dönüştürmenize olanak tanır. Esneklik için bunları jeneriklerle birleştirin:


type OptionsFlags = {
  [K in keyof T]: boolean;
};

interface FeatureFlags {
  darkMode: boolean;
  notifications: boolean;
}

// Her özellik bayrağının etkin (true) veya devre dışı (false) olduğu bir tip oluşturun
let featureFlags: OptionsFlags = {
  darkMode: true,
  notifications: false,
};

OptionsFlags tipi, jenerik bir T tipi alır ve T'nin özelliklerinin artık boolean değerlere eşlendiği yeni bir tip oluşturur. Bu, yapılandırmalar veya özellik bayrakları ile çalışmak için çok güçlüdür.

Küresel Uygulama: Bu desen, bölgeye özgü ayarlara dayalı yapılandırma şemaları oluşturmaya olanak tanır. Bu yaklaşım, geliştiricilerin bölgeye özgü yapılandırmaları (örneğin, bir bölgede desteklenen diller) tanımlamasına olanak tanır. Küresel uygulama yapılandırma şemalarının kolayca oluşturulmasını ve bakımını sağlar.

10. `infer` Anahtar Kelimesi ile Gelişmiş Çıkarım

infer anahtar kelimesi, koşullu tipler içindeki diğer tiplerden tipleri çıkarmanıza olanak tanır.


type ReturnType any> = T extends (...args: any) => infer R ? R : any;

function myFunction(): string {
  return "hello";
}

let result: ReturnType = "hello"; // result string tipindedir

Bu örnek, infer anahtar kelimesini kullanarak bir fonksiyonun dönüş tipini çıkarır. Bu, daha gelişmiş tip manipülasyonu için sofistike bir tekniktir.

Küresel Önem: Bu teknik, büyük, dağıtılmış küresel yazılım projelerinde karmaşık fonksiyon imzaları ve karmaşık veri yapılarıyla çalışırken tip güvenliği sağlamak için hayati olabilir. Tiplerin diğer tiplerden dinamik olarak üretilmesine olanak tanıyarak kodun sürdürülebilirliğini artırır.

En İyi Uygulamalar ve İpuçları

Sonuç: Jeneriklerin Gücünü Küresel Olarak Benimsemek

TypeScript jenerikleri, sağlam ve sürdürülebilir kod yazmanın temel taşlarından biridir. Bu gelişmiş desenlerde ustalaşarak, JavaScript uygulamalarınızın tip güvenliğini, yeniden kullanılabilirliğini ve genel kalitesini önemli ölçüde artırabilirsiniz. Basit tip kısıtlamalarından karmaşık koşullu tiplere kadar, jenerikler küresel bir kitle için ölçeklenebilir ve sürdürülebilir yazılımlar oluşturmak için ihtiyacınız olan araçları sağlar. Unutmayın ki jenerik kullanma prensipleri, coğrafi konumunuzdan bağımsız olarak tutarlı kalır.

Bu makalede tartışılan teknikleri uygulayarak, daha iyi yapılandırılmış, daha güvenilir ve kolayca genişletilebilir kodlar oluşturabilir, sonuçta dahil olduğunuz ülke, kıta veya iş ne olursa olsun daha başarılı yazılım projelerine yol açabilirsiniz. Jenerikleri benimseyin, kodunuz size teşekkür edecektir!