TypeScript’te benzer tip bildirimleri tekrarlanınca girdi tipinden sonuç tipini hesaplamanın yolları aranır. Önemli olan kısalan karakter sayısından çok tipler arasındaki ilişkinin okura açık olmasıdır. Bu yazı, hayalî bir teslimat bildirim hizmetiyle koşullu tipleri ve infer’i inceler; bunları dış verinin gerçekten doğru olup olmadığını doğrulamaktan ayırır.
1. Koşullu tip, girdisi tip olan bir dallanmadır
Resmî koşullu tip belgesi, extends koşuluna göre sonuç tipini seçme sözdizimini açıklar. Aşağıdaki örnek, tipin dize olup olmadığına göre bir boolean değişmez tipi üretir. Çalışma sırasında dizeyi kontrol eden bir işlev değildir.
type IsText<T> = T extends string ? true : false;
type NameIsText = IsText<'parcel'>; // true
type CountIsText = IsText<3>; // false
Teslimat bildirimini oluşturan işlevin dize tanımlayıcı, iç işleme işlevinin sayı tanımlayıcı aldığını varsayalım. Koşullu tipten önce, iki tanımlayıcıyı neden ayırdığınızı açıklayabilmelisiniz. Gerçekten farklı anlamları varsa ayrı adlar yardımcı olur; yalnızca yazım farkıysa girdi biçimini birleştirmek daha okunaklı olabilir. Veri tasarımındaki belirsizliği tip teknikleriyle örtmeyin.
Tipi incelerken beklenen girdileri ve sonuçları çiftler hâlinde yazın. Dize, sayı, birleşim ve beklenmedik girdileri küçük örneklere ayırmak, karmaşık bildirimi okuma yükünü azaltır. Yorumda yazılan sonuçla düzenleyicinin çıkardığı tipin aynı olduğunu da kontrol edin. Tip adı doğal görünse de gerçek hesaplama sonucu farklı olabilir.
2. Birleşim dağılımı, dizinin anlamını değiştirir
Tip parametresi doğrudan koşulun solunda olduğunda koşul birleşimin her üyesine uygulanır; buna dağılım denir. Bunu önleyip bütün birleşimi tek birim saymak istiyorsanız köşeli parantezle çevrili biçimi karşılaştırabilirsiniz.
type SeparateLists<T> = T extends unknown ? T[] : never;
type Together<T> = [T] extends [unknown] ? T[] : never;
type A = SeparateLists<string | number>; // string[] | number[]
type B = Together<string | number>; // (string | number)[]
const a: A = ['a', 'b'];
const b: B = ['a', 1];
İlki yalnızca dizeler içeren dizi veya yalnızca sayılar içeren dizidir. İkincisinde tek dizide dizelerle sayılar birlikte bulunabilir. Teslimat listesinin bütünü tek kod türü mü taşımalı, yoksa her öğe farklı türe izin verebilir mi sorusuna göre uygun sonuç değişir. Ekranda ikisinde de köşeli parantez vardır; ancak iki dizinin sözleşmesi aynı değildir.
Uygulamada sorun çıkarsa karmaşık yardımcı tipin tamamını okumak yerine girdiyi birer üye olarak deneyin. Dize, sayı ve iki tipin birleşimi için sonuçları karşılaştırın. Dağılımın amaçlanıp amaçlanmadığı açık olunca köşeli parantez ekleme nedeni de açıklanabilir. Tip incelemesinde yalnızca son sonucu değil, izin vermek istediğiniz değer örneklerini de kaydetmek yararlıdır.
3. infer, yapı içindeki tipe ad verip çıkarır
infer, koşullu tipte eşleştirilen yapının bir bölümüne ad vermek için kullanılır. Aşağıdaki örnek, Promise’in tek katmanını açan küçük bir tiptir.
type OneResult<T> = T extends Promise<infer Value> ? Value : T;
type Parcel = OneResult<Promise<{ tracking: string }>>;
type ParcelList = OneResult<Promise<string[]>>;
Bu kod asenkron işi yürütmez veya beklemez. Yalnızca sonucun biçimini derleme aşamasında ifade eder. İşleve Resolved gibi bir ad vermek, gerçek değerin çoktan geldiği izlenimini yaratabilir; bu nedenle tipin nerede kullanıldığı bağlamıyla birlikte değerlendirilmelidir. Çalışma sırasındaki bekleme hâlâ asenkron kodla işlenmelidir.
Özyinelemeli olarak beklenen sonuç tipi gerekiyorsa tek katmanlı eğitim örneğini genişletmeden önce standart yardımcı tip Awaited belgesine bakın. Eğitim tipinin sadeliğiyle ortak aracın gereksinimleri farklıdır. Ekibe yeni yardımcı tip getiriyorsanız standart tipten farklı sonuç veren girdileri ve bu farkın neden gerekli olduğunu belgelemek yararlıdır.
4. Şablon değişmezleriyle olay adlarını bağlamak
Şablon değişmez tipleri, dize değişmezlerinin birleşimlerini tip olarak ifade eder. Teslimat hizmetinde alanla eylemi birleştiren olay adları örnek olabilir.
type Scope = 'parcel' | 'address';
type Action = 'created' | 'updated';
type EventName = `${Scope}:${Action}`;
const event: EventName = 'parcel:created';
Yazım hatalı adlar derleme sırasında bulunabilir; ancak bütün olası olay birleşimlerinin gerçek hizmette geçerli olması ayrı konudur. Örneğin yalnızca adres silme olayı destekleniyorsa basit alan ve eylem çarpımı kuralı tam ifade etmeyebilir. Böyle durumda önce izin verilen olaylarla payload’ı açıkça eşleyen bir tasarım düşünün.
Olaylar çoğaldığında okurun gerçek adları kolayca bulması da önemlidir. Birçok otomatik birleştirme kuralını zincirlemek yerine dış sistemlere aktarılan adları tek dosyada görünür tutabilirsiniz. Soyutlama öncesi ve sonrasında yeni ekip üyesinin yanlış olayı nasıl bulacağını karşılaştırın. Tip inceliğiyle kullanılabilirlik birlikte değerlendirilmelidir.
5. Dış JSON çalışma sırasında kontrol edilmelidir
API yanıtına User veya Parcel tipi koymak, gerçek yanıtın o yapıda olduğunu tek başına garanti etmez. Dış değeri unknown olarak alıp gereken alanları kontrol eden basit biçime bakalım.
function hasTracking(value: unknown): value is { tracking: string } {
return typeof value === 'object' && value !== null
&& 'tracking' in value && typeof value.tracking === 'string';
}
const incoming: unknown = { tracking: 'DEMO-001' };
if (hasTracking(incoming)) console.log(incoming.tracking);
Bu kontrol yalnızca tracking alanının dize olduğunu doğrular. Takip numarasının gerçekten var olduğunu veya kullanıcının o teslimatı görme yetkisi bulunduğunu doğrulamaz. Tip daraltmayı, iş kurallarını ve yetki kontrolünü ayrı sorumluluklar olarak düşünün. Resmî Narrowing belgesi, koşullar yoluyla tip bilgisinin daralmasını açıklar.
6. Tip araçlarını seçmek için küçük bir inceleme sırası
Önce izin verilecek iki gerçek değeri ve reddedilecek iki değeri yazın. Ardından sıradan birleşimlerle açık nesne bildirimleri kullanarak anlamı ifade edin. Tekrarlanan ilişki kaldığında koşullu tip veya infer kullanmak, tekniğin neden eklendiğini belirginleştirir. Bildirimi okuma süresi çok artıyorsa yalnızca ortak bölümü çıkarıp kalanını sıradan tiplerle bırakabilirsiniz.
Son olarak tip kontrolünü ve çalışma zamanı kontrolünü ayrı yürütün. Derleyicinin yanlış olay adını reddetmesiyle sunucu eksik alan gönderdiğinde programın hatayı açıklaması birbirini tamamlar. Küçük örnek sonuçlarını gördükten sonra gerçek girdi sınırına bağlamak, tip dönüşümünün güvenli uygulama tasarımına katkı vermesini sağlar.