Tip daraltma (type narrowing), TypeScript'in kodun daha önce yaptığı kontrollere dayanarak kodun belirli bir noktasında bir değer için daha özel bir tip bulmasıdır. Bir string | number parametresi if (typeof x === "string") içinde string, else içinde number olur.
Kontrolden önce value.toFixed(2) çağırmak bir derleme hatası olurdu, çünkü toFixed metodu string üzerinde yoktur. Kontrol sıradan JavaScript'tir ve çalışma zamanında çalışır; daraltma ise derleyicinin onu okuyup tipi ayarlamasıdır. Fazladan hiçbir şey üretilmez.
Kontrol Akışı Analizi
TypeScript bir fonksiyondaki her yolu izler: if/else, erken return ve throw, switch, döngüler ve kısa devre operatörleri &&, ||, ?? ve ?:. Her noktada bir değişkenin tipi, orada hâlâ mümkün olan şeydir.
Erken return stili ("guard clause'lar") daraltmanın en okunaklı yoludur: önce tuhaf durumları ele alın, fonksiyonun geri kalanı temiz tiple çalışsın.
Daraltmanın Tüm Yolları
| Biçim | Örnek | Daralttığı |
|---|---|---|
| typeof | typeof x === "string" | primitive'ler ve fonksiyonlar |
| Truthiness | if (x) | null, undefined ve falsy literal'leri çıkarır |
| Eşitlik | x === "a", x == null, x !== undefined | literal'ler, null, undefined |
in | "swim" in pet | özelliğe göre nesne union'ları |
| instanceof | err instanceof TypeError | sınıf örnekleri |
Array.isArray | Array.isArray(x) | diziler ve geri kalan her şey |
| Atama | x = 5 | atanan tipe |
| Type predicate | function isUser(x: unknown): x is User | kontrol edebileceğiniz her şey |
| Assertion fonksiyonu | function assertUser(x: unknown): asserts x is User | çağrıdan sonraki her şey |
| Ayırıcı özellik | switch (shape.kind) | etiketli union'lar |
Son üçü type guard'lar ve discriminated union'lar sayfalarında anlatılıyor. Geri kalanlar aşağıda.
Truthiness ile Daraltma
if (x), null ve undefined tiplerini (ve false, 0, "" literal tiplerini) çıkarır. Kısadır ve klasik bir tuzağı vardır: 0 ve "" falsy'dir, bu yüzden geçerli değerler eksikmiş gibi ele alınır.
Sayılar ve string'ler için açıkça undefined veya null ile karşılaştırın (ya da ?? kullanın). Truthiness, hiçbir zaman falsy olmayan nesneler, diziler ve fonksiyonlar için uygundur.
Eşitlik ile Daraltma
===, !==, == ve != iki tarafı da daraltır. Bir literal ile karşılaştırmak o literal'e daraltır; == null (gevşek eşitlik) tek bir kontrolde hem null hem undefined ile eşleşir ve gevşek eşitliğin alışılmış olduğu tek yerdir.
İki değişkeni karşılaştırmak ikisini de ortak olabilecekleri şeye daraltır: a: string | number ve b: string | boolean değerleri a === b kontrolünden geçerse if içinde ikisi de string olur.
in Operatörü
"key" in obj, nesne tiplerinden oluşan bir union'ı o özelliğe sahip olan (ya da sahip olabilecek) üyelere daraltır.
in, bir nesne olduğunu bildiğiniz anda unknown üzerinde de çalışır: typeof v === "object" && v !== null && "id" in v sonrasında TypeScript, v değerinin unknown tipinde bir id özelliğine sahip olduğunu bilir. Kendi tasarladığınız union'lar için ortak bir etiket özelliği (kind: "fish"), metotları yoklamaktan daha anlaşılırdır: bu kalıba discriminated union denir.
Atama ile Daraltma
Bir değişkenin bildirilmiş bir tipi ve atamalarını izleyen daraltılmış bir tipi vardır. Bir değer atamak, onu bildirilmiş tiple sınırlı olmak üzere o değerin tipine daraltır.
Daraltmanın Kaybolduğu Yerler
Daraltma yereldir ve temkinlidir. Birkaç durum onu sıfırlar:
- Farklı bir ifade.
obj.namekontrolüobj.name(veobj["name"]) ifadesini daraltır, amakeybir literal değil de birstringdeğişkeni olduğundaobj[key]ifadesini ve kontrolden önce alınmış bir kopyayı daraltmaz. - Callback'ler ve yeniden atama. Bir callback'in içinde, daraltılmış bir
letyalnızca callback oluşturulduktan sonra yeniden atanmıyorsa daraltmasını korur. Birconstya da hiç yeniden atanmayan bir parametre daraltılmış kalır. - Yardımcılarda gizlenmiş kontroller.
isString(x: unknown): booleanşeklindeki bir fonksiyon derleyiciye hiçbir şey söylemez. Onax is stringşeklinde bir type predicate dönüş tipi verin, çağrılarıtypeofgibi daraltır.
Derleyici index.ts(5,38): error TS18048: 'x' is possibly 'undefined'. bildirir. Callback daha sonra, x = undefined sonrasında çalışabilir. O son atamayı silin (ya da değeri if içinde bir const değişkenine kopyalayın), kod derlenir ve iki kez 5 yazdırır.
boolean döndüren bir yardımcı, neyi kanıtladığını bildirerek düzeltilebilir. Type guard budur:
function isString(value: unknown): value is string {
return typeof value === "string";
}
TypeScript 5.5'ten beri derleyici basit arrow function'lar için bu tür predicate'leri çıkarır; list.filter((x) => x !== undefined) ifadesinin artık undefined içermeyen bir dizi döndürmesinin nedeni budur.
Sıkça Sorulan Sorular
TypeScript'te tip daraltma nedir?
Daraltma, TypeScript'in kodun yaptığı bir kontrole dayanarak bir blok içinde bir değişkenin tipini inceltmesidir. if (typeof x === "string") sonrasında bir string | number, if içinde yalnızca string, else içinde yalnızca number olur. Derleyici her noktadaki tipi bulmak için if, else, return, switch, &&, || ve ?: yapılarını izler; buna kontrol akışı analizi denir.
TypeScript tipimi neden daraltmıyor?
Yaygın nedenler: kontrol, kullandığınızdan farklı bir ifade üzerinde yapılmıştır (obj.a kontrol edilmiş, tipi string olan bir key ile obj[key] kullanılmış); değer, bir callback oluşturulduktan sonra yeniden atanan bir let değişkenidir ve callback daraltmayı kaybeder; ya da kontrol, x is T type predicate'i yerine düz boolean döndüren bir yardımcının içinde gizlidir.
Tip daraltma çalışma zamanında çalışır mı?
Kontroller çalışır: typeof, instanceof, in ve === çalışan sıradan JavaScript'tir. Daraltmanın kendisi ise yalnızca derleme zamanındadır. TypeScript çalışma zamanı kontrollerinizi okur ve statik tipleri onlara göre ayarlar; üretilen JavaScript'e hiçbir şey eklenmez.
TypeScript'te bir unknown tip nasıl daraltılır?
Aynı kontrollerle: typeof value === "string", Array.isArray(value), value instanceof Date ya da nesneler için typeof value === "object" && value !== null && "id" in value. Yeniden kullanılabilir kontroller için value is T dönüş tipli bir type guard fonksiyonu yazın.
TypeScript'te bir diziden undefined değerleri nasıl filtrelerim?
items.filter((x) => x !== undefined), TypeScript 5.5'ten beri undefined içermeyen bir T[] döndürür, çünkü callback'i bir type predicate olarak çıkarır. Eski sürümlerde predicate'i kendiniz yazın: items.filter((x): x is T => x !== undefined).