Soru tarihi: TypeScript, geliştiricilerin nesnelerin belirli bir türe uyup uymadığını kontrol eden kendi kullanıcı tanımlı işlevlerini (type guards) oluşturmasına olanak tanıyarak normal tür kontrollerini genişletir. Bu, bir değer türünün farklı olabileceği birim türleri, dinamik yapılar ve API'ler ile çalışmak için gereklidir.
Sorun genellikle, typeof ve instanceof ile yapılan normal tür kontrollerinin yalnızca ilkel türler ve sınıflar ile sınırlı olmasıdır; yapılar veya karmaşık türler bununla belirlenemez. Derleyiciye güvenli bir şekilde hangi durumlarda bir değerin istenen türe daraltıldığını açıkça belirtmek gerekir.
Çözüm - return tipinde bir type predicate olan function isCat(obj: Animal): obj is Cat {...} biçiminde koruyucu işlevler yazmaktır.
Kod örneği:
interface Dog { bark: () => void; } interface Cat { meow: () => void; } type Pet = Dog | Cat; function isDog(pet: Pet): pet is Dog { return (pet as Dog).bark !== undefined; } function makeSound(pet: Pet) { if (isDog(pet)) { pet.bark(); } else { pet.meow(); } }
Anahtar özellikler:
Type guard fonksiyonunda true/false döndürmek yeterli midir ki derleyici türü daraltsın?
Hayır. Dönüş türünü type predicate (örneğin, pet is Dog) biçiminde açıkça belirtmek önemlidir; aksi takdirde TypeScript, değerin türünü otomatik olarak daraltmayacaktır, hatta fonksiyon sadece true veya false döndürse bile.
Type guard'ı callback içinde (örneğin, filter'da) kullanmak mümkün mü ve daraltma doğru çalışacak mı?
Evet, type guard doğru şekilde anotasyona sahipse, derleyici filter sonrasında ve forEach/callback fonksiyonlarının içinde dizi elemanlarının türünü daraltır. Ancak anotasyon yoksa veya yanlış yazılmışsa, sonuç birim (union) tür olarak kalır; belirli bir tür elde edilemez.
const pets: Pet[] = [...]; const dogs = pets.filter(isDog); // TypeScript, dogs: Dog[] olduğunu biliyor
Kullanıcı tanımlı type guard'lar, typeof ve instanceof ile yapılan normal tür kontrollerinden ne farkla ayrılır?
Type guard fonksiyonları, herhangi bir yapının kontrolünü gerçekleştirmeyi, herhangi bir karmaşıklıkta kontrolleri tanımlamayı ve sınıfsız arayüzleri işlemeyi sağlar, sadece temel türler ve sınıflarla sınırlı değildir.
Fonksiyon, type predicate olmadan kullanıcıları filtreler:
function isValidAdmin(user: any): boolean { return user.isAdmin === true; } const admins = users.filter(isValidAdmin); // admins: any[]
Artılar:
Eksiler:
Fonksiyon, doğru type predicate ile filtreleme yapar:
interface Admin { name: string; isAdmin: true; } function isAdmin(user: any): user is Admin { return user && user.isAdmin === true; } const admins = users.filter(isAdmin); // admins: Admin[]
Artılar:
Eksiler: