TypeScript'te null ve undefined değerlerinin nasıl ele alındığını strictNullChecks seçeneği belirler. Seçenek açıkken null ve undefined kendi ayrı tipleridir; string tipindeki bir değişkene null atayamaz, T | undefined tipindeki bir değeri kontrol etmeden kullanamazsınız. TypeScript 6.0 ile strict varsayılan olarak açık geldiği için, strict ailesinin parçası olan strictNullChecks da yeni projelerde varsayılan olarak açıktır.

Bu yazıda null kontrollerinin dört aracını göreceksiniz: daraltma (narrowing), optional chaining (?.), nullish coalescing (??) ve non-null assertion (!). Son bölümde isteğe bağlı özelliklerde "eksik" ile "undefined değerli" ayrımını yapan exactOptionalPropertyTypes seçeneğine bakacağız. Örnekler TypeScript 6.0 ile derlendi ve Node.js 24 ile çalıştırıldı.

strictNullChecks açık ve kapalı

strictNullChecks açık ve kapalı: let s: string = null, find() dönüş tipi, Kontrolsüz özellik erişimi, Opsiyonel parametre x?: number

Array.prototype.find eşleşme bulamazsa undefined döndürür. strictNullChecks açıkken TypeScript bunu dönüş tipine yansıtır ve kontrol etmeden kullanmanıza izin vermez:

typescript
const kullanicilar = [
  { ad: "Deniz", yas: 28 },
  { ad: "Ece", yas: 35 },
];

const bulunan = kullanicilar.find((k) => k.ad === "Can");
console.log(bulunan.yas);
// TS18048: 'bulunan' is possibly 'undefined'.

let sayi: number = null;
// TS2322: Type 'null' is not assignable to type 'number'.

Aynı dosyayı --strictNullChecks false ile derlediğinizde hiçbir hata çıkmaz. tsconfig belgesinin anlattığı gibi bu modda null ve undefined tip sisteminde fiilen yok sayılır ve hata çalışma zamanına kalır. Handbook, uygulanabildiği her projede seçeneğin açılmasını öneriyor.

DurumstrictNullChecks: falsestrictNullChecks: true
let s: string = nullKabul edilirTS2322
find() dönüş tipiTT | undefined
Kontrolsüz özellik erişimiDerlenir, çalışırken çökebilirTS18048 / TS2532
Opsiyonel parametre x?: numbernumbernumber | undefined

Daraltma ile null kontrolü

En güvenli yol, değeri kullanmadan önce kontrol etmektir. TypeScript kontrol akışını izler ve if bloğunun içinde değişkenin tipini daraltır:

typescript
function selamla(ad: string | null) {
  if (ad === null) {
    return "Merhaba, misafir";
  }
  return "Merhaba, " + ad.toUpperCase(); // burada ad: string
}
console.log(selamla(null));     // Merhaba, misafir
console.log(selamla("zeynep")); // Merhaba, ZEYNEP

function uzunluk(metin?: string) {
  if (!metin) return 0; // undefined ve "" elenir
  return metin.length;
}
console.log(uzunluk(), uzunluk(""), uzunluk("abc")); // 0 0 3

Doğruluk (truthiness) kontrolü boş metni ve 0 değerini de eler; bu istediğiniz şey değilse açık karşılaştırma yapın. == null ise hem null hem undefined değerini yakalar:

typescript
function kontrolEt(deger: string | null | undefined) {
  if (deger == null) {
    return "boş"; // null ve undefined birlikte elenir
  }
  return deger.trim();
}
console.log(kontrolEt(null), kontrolEt(undefined), kontrolEt(" x ")); // boş boş x

Daraltmanın diğer biçimleri (typeof, in, instanceof, type predicate) için narrowing ve type guard yazısına, == ile === farkı için JavaScript eşitlik operatörleri yazısına bakın.

Optional chaining ve nullish coalescing

Optional chaining ve nullish coalescing

TypeScript 3.7 ile gelen ?., solundaki değer null veya undefined ise ifadeyi durdurup undefined döndürür. Özellik erişimi (a?.b), indeks erişimi (a?.[0]) ve çağrı (f?.()) biçimleri vardır. ?? ise yalnızca sol taraf null veya undefined olduğunda sağdaki değeri verir; || gibi 0 ve boş metni yok saymaz:

typescript
interface Siparis {
  musteri?: { adres?: { sehir: string } };
  notlar?: string[];
  bildir?: () => string;
}

const s: Siparis = { musteri: {} };

console.log(s.musteri?.adres?.sehir);        // undefined
console.log(s.notlar?.[0]);                   // undefined
console.log(s.bildir?.());                    // undefined
console.log(s.musteri?.adres?.sehir ?? "-");  // -

const adet = 0;
console.log(adet || 10, adet ?? 10);          // 10 0

Sürüm notlarının vurguladığı bir ayrıntı: ?. yalnızca hemen solundaki değeri kontrol eder. foo?.bar.baz() ifadesinde bar undefined ise yine hata alırsınız. Operatörlerin JavaScript tarafındaki davranışı optional chaining ve nullish coalescing yazısında ayrıntılı anlatılıyor.

Non-null assertion (!) ve riskleri

Bir ifadenin sonuna ! eklemek, TypeScript'e "bu değer null veya undefined değil" demektir ve tipten null | undefined kısmını çıkarır. Bu bir tür type assertion'dır: derleme sonrası silinir, çalışma zamanında hiçbir kontrol yapmaz. Yanılırsanız hata yine oluşur:

typescript
const ayarlar = new Map<string, string>([["dil", "tr"]]);

const dil = ayarlar.get("dil")!; // string
console.log(dil.toUpperCase());  // TR

const tema = ayarlar.get("tema")!; // derleyici susar, değer yine undefined
console.log(tema.toUpperCase());
// Node.js: TypeError: Cannot read properties of undefined (reading 'toUpperCase')

Map.get ve has() tuzağı

Map.prototype.get anahtar yoksa undefined döndürür, bu yüzden dönüş tipi V | undefined olarak tanımlıdır. Sık yapılan bir hata, önce has() ile kontrol edip ardından get() sonucunu doğrudan kullanmaktır. İki çağrı arasında bağ kurulmadığı için TypeScript has() kontrolüyle get() sonucunu daraltmaz:

typescript
const onbellek = new Map<string, { deger: number }>();
onbellek.set("a", { deger: 1 });

if (onbellek.has("a")) {
  console.log(onbellek.get("a").deger);
  // TS2532: Object is possibly 'undefined'.
}

const kayit = onbellek.get("a");
if (kayit) {
  console.log(kayit.deger); // 1
}

Doğru kalıp, get() sonucunu bir değişkene alıp o değişkeni kontrol etmektir. Bu hem tek bir arama yapar hem de daraltmayı mümkün kılar. Aynı mantık, index signature üzerinden yapılan okumalar için de geçerlidir; noUncheckedIndexedAccess açıkken düz nesne okumaları da undefined içerir. Ayrıntılar index signature ve Record yazısında.

Atanmadan kullanılan değişkenler

strictNullChecks açıkken TypeScript, tipinde undefined olmayan bir let değişkeninin her yolda atanıp atanmadığını da izler:

typescript
let sonuc: number;
if (Math.random() > 2) {
  sonuc = 1;
}
console.log(sonuc);
// TS2454: Variable 'sonuc' is used before being assigned.

exactOptionalPropertyTypes: eksik ile undefined farkı

Varsayılan olarak takmaAd?: string tanımı takmaAd?: string | undefined gibi yorumlanır; özelliği hiç yazmamak ile undefined değeriyle yazmak aynı sayılır. Ancak JavaScript bu ikisini ayırt eder: in operatörü, Object.keys, spread ve for...in farklı sonuç verir:

typescript
interface Profil {
  ad: string;
  takmaAd?: string;
}

const p1: Profil = { ad: "Ali" };
const p2: Profil = { ad: "Ali", takmaAd: undefined };
console.log("takmaAd" in p1, "takmaAd" in p2); // false true

TypeScript 4.4 ile gelen exactOptionalPropertyTypes açıldığında, isteğe bağlı özelliğe undefined açıkça yazılmadıkça atanamaz:

typescript
// tsc --noEmit --exactOptionalPropertyTypes profil.ts
const p2: Profil = { ad: "Ali", takmaAd: undefined };
// TS2375: Type '{ ad: string; takmaAd: undefined; }' is not assignable to type
// 'Profil' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined'
// to the types of the target's properties.

interface Tercih { tema?: "koyu" | "acik" }
declare const t: Tercih;
t.tema = undefined;
// TS2412: Type 'undefined' is not assignable to type '"koyu" | "acik"' with
// 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type
// of the target.

Bilerek undefined kabul etmek istediğiniz özellikte tipi takmaAd?: string | undefined olarak yazarsınız. Bu seçenek de strict ailesinde değildir, ayrıca açılması gerekir.

json
{
  "compilerOptions": {
    "strict": true,
    "exactOptionalPropertyTypes": true
  }
}

Sık yapılan hatalar

Sık yapılan hatalar: Hata mesajını susturmak için her yere ! eklemek. Hata derleme anından çalışma..., || ile varsayılan değer vermek. 0, "" ve false geçerli değerlerse ??...
  • Hata mesajını susturmak için her yere ! eklemek. Hata derleme anından çalışma anına taşınır.
  • || ile varsayılan değer vermek. 0, "" ve false geçerli değerlerse ?? kullanın.
  • if (deger) kontrolünün sayılar için 0 değerini de elediğini unutmak.
  • Eski bir projede strictNullChecks kapalıyken yazılmış kodu, seçeneği açınca tek seferde düzeltmeye çalışmak. Dosya dosya ilerlemek genellikle daha yönetilebilirdir; JavaScript projesini TypeScript'e geçirme yazısında kademeli geçiş anlatılıyor.

Sık Sorulan Sorular

null mu undefined mı kullanmalıyım?

TypeScript belgeleri ikisinden birini zorunlu tutmaz; ikisi de "değer yok" anlamında kullanılır. Önemli olan proje içinde tutarlı olmak ve tipte hangisinin beklendiğini açıkça yazmaktır.

TypeScript 6.0'da strictNullChecks varsayılan olarak açık mı?

6.0 sürüm notlarına göre strict artık varsayılan olarak true. strictNullChecks strict ailesinde olduğu için tsconfig.json içinde aksini yazmadığınız sürece açıktır. Ayrıntılar TypeScript 6.0 yenilikleri yazısında.

TS2532 ile TS18048 arasındaki fark nedir?

İkisi de "değer undefined olabilir" uyarısıdır. İfade adlandırılabiliyorsa (örneğin bulunan veya o.a) TS18048 ('x' is possibly 'undefined'), adlandırılamıyorsa (örneğin bir fonksiyon çağrısının sonucu) TS2532 (Object is possibly 'undefined') görürsünüz. Sık görülen diğer hatalar için TypeScript sık hatalar yazısına bakın.

Optional chaining null değerde null mı döndürür?

Hayır. 3.7 sürüm notlarının tarifine göre ?. solundaki değer null veya undefined ise ifadeyi durdurup her iki durumda da undefined döndürür. Kodunuz sonucu === null ile karşılaştırıyorsa bu fark önemlidir; == null veya ?? ikisini birlikte yakalar.

typescript
type K = { profil: { ad: string } } | null;
const kullanici = null as K;
console.log(kullanici?.profil.ad); // undefined

Opsiyonel parametre ile varsayılan değerli parametre aynı mı?

İçeride hayır. x?: number fonksiyon gövdesinde number | undefined tipindedir; x = 5 yazarsanız gövdede number olur, çünkü eksik değer varsayılanla doldurulur.

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 · Narrowing ve type guard · Strict modu · Type assertion · noUncheckedIndexedAccess · Optional chaining ve ?? · TypeScript ileri seviye