TypeScript'te narrowing (daraltma), derleyicinin kodunuzdaki kontrollere bakarak bir değişkenin tipini o noktada daha dar bir tipe indirmesidir. typeof, doğruluk (truthiness) kontrolü, === ve != karşılaştırmaları, in, instanceof, atamalar, kendi yazdığınız x is T dönüşlü fonksiyonlar (type predicate) ve asserts imzalı fonksiyonlar bu işi yapar. Bu kontrollerin her birine type guard denir. Tüm olasılıklar elendiğinde kalan tip never olur ve bu, eksik durumları yakalamak için kullanılır.

Aşağıda her tekniği küçük bir örnekle ve hangi tuzağa düşebileceğinizle birlikte anlatıyoruz. Örnekler TypeScript 6.0.3 ile tsc --strict --target es2022 --moduleDetection force seçenekleriyle derlendi; hata kodları ve mesajları bu derleyicinin gerçek çıktısıdır. TypeScript 6.0'da strict varsayılan olarak açık geldiği için null ve undefined ayrı tipler olarak ele alınır; örneklerdeki "possibly null" hataları bu yüzden görünür. Konunun temeli olan union tipleri için union ve intersection yazısına bakabilirsiniz.

Daraltma nasıl çalışır?

Daraltma nasıl çalışır?

Derleyici kodunuzu yalnızca satır satır okumaz; programın izleyebileceği yolları da takip eder. Buna control flow analysis (kontrol akışı analizi) denir. Bir if dalında return ettiğinizde, fonksiyonun geri kalanında o dalın koşulunun sağlanmadığını bilir:

typescript
function solaDoldur(dolgu: number | string, metin: string): string {
  if (typeof dolgu === "number") {
    return " ".repeat(dolgu) + metin; // dolgu: number
  }
  return dolgu + metin; // dolgu: string
}

console.log("[" + solaDoldur(3, "ts") + "]"); // [   ts]
console.log(solaDoldur(">> ", "ts")); // >> ts

typeof ile daraltma

JavaScript'in typeof operatörü şu metinlerden birini döndürür: "string", "number", "bigint", "boolean", "symbol", "undefined", "object" ve "function". TypeScript bu değerlerle yapılan karşılaştırmaları type guard olarak tanır. Dikkat edilecek nokta, typeof null değerinin "object" olmasıdır; derleyici bu tarihî tuhaflığı bilir ve sizi uyarır:

typescript
function hepsiniYaz(x: string | string[] | null) {
  if (typeof x === "object") {
    for (const s of x) {
      console.log(s);
    }
  }
}
// TS18047: 'x' is possibly 'null'.

typeof x === "object" dalında tip string[] | null olarak kalır. null'ı ayrıca elemeniz gerekir; bunun iki yolunu aşağıda görüyoruz.

Truthiness (doğruluk) ile daraltma

if, &&, || ve ! koşulu önce boolean'a çevirir. 0, NaN, boş string, 0n, null ve undefined yanlış (falsy) sayılır. TypeScript bu kontrolle null ve undefined'ı eler:

typescript
function hepsiniYaz(x: string | string[] | null) {
  if (x && typeof x === "object") {
    console.log(x.join(","));
  } else if (typeof x === "string") {
    console.log("metin:", x);
  } else {
    console.log("boş");
  }
}

hepsiniYaz(["a", "b"]); // a,b
hepsiniYaz("c"); // metin: c
hepsiniYaz(""); // metin:
hepsiniYaz(null); // boş

Eşitlik ile daraltma

===, !==, ==, != ve switch da tip daraltır. İki değişken eşitse tipleri de ortak olmalıdır; aşağıda tek ortak tip string olduğu için iki değişken de o dalda string olur. != null ise hem null'ı hem undefined'ı eler:

typescript
function karsilastir(x: string | number, y: string | boolean) {
  if (x === y) {
    return x.toUpperCase() + y.toLowerCase(); // ikisi de string
  }
  return "eşit değil";
}

function carp(deger: number | null | undefined, kat: number) {
  if (deger != null) {
    return deger * kat; // deger: number
  }
  return 0;
}

console.log(karsilastir("ab", "ab")); // ABab
console.log(carp(undefined, 3), carp(4, 3)); // 0 12

in operatörü ile daraltma

in operatörü ile daraltma

"ozellik" in nesne kontrolü, union'ın üyelerinden o özelliğe sahip olanları doğru dala, sahip olmayanları yanlış dala ayırır. İsteğe bağlı bir özelliği olan tip ise iki dalda da kalır:

typescript
type Balik = { yuz: () => string };
type Kus = { uc: () => string };
type Insan = { yuz?: () => string; uc?: () => string };

function hareket(h: Balik | Kus) {
  if ("yuz" in h) {
    return h.yuz(); // h: Balik
  }
  return h.uc(); // h: Kus
}

function hareket2(h: Balik | Kus | Insan) {
  if ("yuz" in h) {
    h; // h: Balik | Insan
  } else {
    h; // h: Kus | Insan
  }
}

console.log(hareket({ uc: () => "uçuyor" })); // uçuyor

TypeScript 4.9 ile in daha da kullanışlı hâle geldi: Hiçbir üyede listelenmeyen bir özelliği kontrol ettiğinizde derleyici nesnenin tipini o özelliği içerecek şekilde genişletir. Bu sayede unknown bir değeri adım adım güvenle inceleyebilirsiniz:

typescript
function paketAdi(veri: unknown): string | undefined {
  if (veri && typeof veri === "object" && "name" in veri && typeof veri.name === "string") {
    return veri.name;
  }
  return undefined;
}

console.log(paketAdi({ name: "keydal-api", version: "1.0.0" })); // keydal-api
console.log(paketAdi(42)); // undefined

instanceof ile daraltma

x instanceof Sinif, Sinif.prototype değerinin x'in prototip zincirinde olup olmadığına bakar. TypeScript bu kontrolü de type guard olarak kullanır; new ile oluşturulan değerlerde ve hata nesnelerinde çok işe yarar:

typescript
function yaz(x: Date | string) {
  if (x instanceof Date) {
    return x.toISOString().slice(0, 10); // x: Date
  }
  return x.toUpperCase(); // x: string
}

console.log(yaz(new Date(Date.UTC(2026, 10, 5)))); // 2026-11-05
console.log(yaz("tarih yok")); // TARIH YOK

Atamalar ve bildirilen tip

Bir değişkene değer atadığınızda derleyici o andan sonra değişkenin tipini atanan değere göre daraltır. Ancak sonraki atamalar her zaman değişkenin ilk bildirilen tipine göre denetlenir:

typescript
let x = Math.random() < 0.5 ? 10 : "merhaba"; // bildirilen tip: string | number
x = 1; // şimdi x: number
x = "hoşça kal"; // geçerli, bildirilen tipte string var
x = true;
// TS2322: Type 'boolean' is not assignable to type 'string | number'.

Type predicate: kendi type guard fonksiyonunuz

Hazır kontroller yetmediğinde dönüş tipi parametre is Tip olan bir fonksiyon yazarsınız. Fonksiyon true döndürdüğünde derleyici argümanı o tipe, false döndürdüğünde kalan tiplere daraltır. Bu fonksiyonlar dizi filter metoduyla da çalışır:

typescript
type Balik = { ad: string; yuz: () => void };
type Kus = { ad: string; uc: () => void };

function balikMi(h: Balik | Kus): h is Balik {
  return (h as Balik).yuz !== undefined;
}

const hayvanlar: (Balik | Kus)[] = [
  { ad: "Nemo", yuz() {} },
  { ad: "Maviş", uc() {} },
];

const baliklar: Balik[] = hayvanlar.filter(balikMi);
console.log(baliklar.map((b) => b.ad)); // [ 'Nemo' ]

TypeScript 5.5'ten itibaren derleyici bazı fonksiyonlar için predicate'i kendisi çıkarır. Sürüm notlarındaki koşullar şunlardır: Fonksiyonun açık bir dönüş tipi olmamalı, tek bir return ifadesi bulunmalı, parametresini değiştirmemeli ve parametreyle ilgili bir daraltmaya bağlı boolean döndürmelidir. Bu sayede aşağıdaki kod artık açıklama gerektirmeden derlenir:

typescript
const degerler = [1, undefined, 3];
const sayilar = degerler.filter((d) => d !== undefined); // number[]

console.log(sayilar.map((n) => n * 2)); // [ 2, 6 ]

Assertion function: asserts ile daraltma

TypeScript 3.7 ile gelen assertion signature'lar, koşul sağlanmazsa hata fırlatan fonksiyonları modeller. İki biçimi vardır: asserts kosul, fonksiyon normal dönerse koşulun doğru olduğunu söyler; asserts deger is Tip ise argümanın o tipte olduğunu söyler. Fonksiyon çağrıldıktan sonraki tüm kodda daraltma geçerli olur:

typescript
function dogrula(kosul: unknown, mesaj: string): asserts kosul {
  if (!kosul) throw new Error(mesaj);
}

function metinOlmali(d: unknown): asserts d is string {
  if (typeof d !== "string") throw new Error("metin değil");
}

function bagir(girdi: unknown) {
  metinOlmali(girdi);
  return girdi.toUpperCase(); // girdi: string
}

function yasKontrol(yas: number | null) {
  dogrula(yas !== null, "yaş yok");
  return yas + 1; // yas: number
}

console.log(bagir("selam"), yasKontrol(41)); // SELAM 42
try {
  bagir(5);
} catch (e) {
  console.log((e as Error).message); // metin değil
}

Assertion fonksiyonlarının bir kısıtı vardır: Çağrılan adın açık bir tip açıklamasıyla bildirilmiş olması gerekir. Tip açıklaması olmayan bir const'a atanmış arrow function ile denediğinizde derleyici hata verir:

typescript
const metinMi = (d: unknown): asserts d is string => {
  if (typeof d !== "string") throw new Error("metin değil");
};

function kullan(x: unknown) {
  metinMi(x);
}
// TS2775: Assertions require every name in the call target to be declared with an explicit type annotation.

Çözüm, sabite açık bir tip vermek (const metinMi: (d: unknown) => asserts d is string = ...) ya da fonksiyonu function bildirimiyle yazmaktır.

never ile kapsamlılık kontrolü

Daraltma bir union'daki tüm seçenekleri elediğinde geriye kalan tip never'dır. never her tipe atanabilir, ama never dışında hiçbir tip ona atanamaz. Bu kural, switch'in tüm durumları kapsadığını derleyiciye kontrol ettirmenin yoludur. Union'a yeni bir üye eklenip switch güncellenmezse default dalındaki atama hata verir ve mesajda eksik tipin adı görünür:

typescript
interface Daire { kind: "daire"; r: number }
interface Kare { kind: "kare"; a: number }
interface Ucgen { kind: "ucgen"; a: number }
type Sekil = Daire | Kare | Ucgen;

function alan(s: Sekil) {
  switch (s.kind) {
    case "daire":
      return Math.PI * s.r ** 2;
    case "kare":
      return s.a ** 2;
    default:
      const _kontrol: never = s;
      return _kontrol;
  }
}
// TS2322: Type 'Ucgen' is not assignable to type 'never'.

case "ucgen" eklendiğinde hata kaybolur. Aynı işi tekrar kullanılabilir bir function eksikDurum(x: never): never yardımcısıyla da yapabilirsiniz; eski handbook bu yöntemi önerir. never tipinin diğer kullanımları için any, unknown, never ve void yazısına bakın.

Teknikleri bir arada görmek

Teknikleri bir arada görmek: typeof, Truthiness, Eşitlik, "yuz" in h
TeknikÖrnekNe zaman
typeoftypeof x === "string"Primitive tipler ve fonksiyonlar
Truthinessif (x)null ve undefined elemek (boş string ve 0 dikkat)
Eşitlikx !== null, x != nullBelirli değerleri ya da null/undefined elemek
in"yuz" in hÖzellik varlığına göre nesne tiplerini ayırmak
instanceofx instanceof DateSınıf örnekleri, Error nesneleri
Ayırt edici alans.kind === "daire"Discriminated union
Type predicateh is BalikTekrar kullanılan özel kontroller, filter
Assertionasserts d is stringKoşul sağlanmazsa hata fırlatan doğrulamalar
neverconst k: never = sTüm durumların ele alındığını kanıtlamak

Sık yapılan hatalar

  • typeof x === "object" ile null'ı elediğini sanmak: null da "object" döndürür.
  • Truthiness ile boş string ve 0'ı kaybetmek: Sayı ve metin parametrelerinde != null çoğu zaman daha doğrudur.
  • Daraltmayı tip assertion ile atlamak: as derleyiciyi susturur ama hiçbir şeyi kontrol etmez; ayrıntısı type assertion yazısında.
  • Assertion function'ı açık tipsiz bir arrow ile yazmak: TS2775 alırsınız.
  • Daraltılmış tipi kalıcı sanmak: Atamayla daralan bir değişkene sonradan bildirilen tipteki başka bir değer atanabilir; atamalar her zaman ilk bildirilen tipe göre denetlenir.

Sık Sorulan Sorular

Type guard ile type predicate aynı şey mi?

Type guard, daraltmaya yol açan her kontrolün genel adıdır (typeof, instanceof gibi). Type predicate ise x is T dönüş tipiyle kendi type guard'ınızı yazmanızı sağlayan sözdizimidir.

Predicate mi assertion function mı kullanmalıyım?

Kontrolün sonucuna göre farklı dallarda farklı işler yapacaksanız predicate (if ile kullanılır). Koşul sağlanmadığında devam etmenin anlamı yoksa ve hata fırlatmak istiyorsanız assertion function daha kısa kod verir.

unknown bir değeri nasıl güvenle kullanırım?

typeof, instanceof, in ve kendi predicate'lerinizle adım adım daraltarak. Bu yaklaşım unknown tipinin varlık sebebidir.

Daraltma çalışma zamanında ek kod üretir mi?

Hayır. Kontrolleri zaten siz JavaScript olarak yazıyorsunuz; TypeScript yalnızca bu kontrolleri okuyup tipleri hesaplar. Yalnızca x is T ve asserts gibi tip açıklamaları çıktıdan silinir.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: TypeScript öğrenme rehberi · Union ve intersection tipleri · any, unknown, never ve void · null, undefined ve strictNullChecks · Type assertion (as) · JavaScript tip dönüşümü · TypeScript ileri seviye yazısı