İçeriğe geç
academia.sh

Ders 03 / 23

any, unknown ve never

Denetimi kapatan any, denetimi zorunlu kılan unknown ve hiçbir değeri olmayan never tipinin atanabilirlik kuralları ve kullanım yerleri.

İçindekiler

Önceki ders ölçüm kaydının ilk tipli sürümünü yazdı, ancak kayıt hâlâ elde yazılmış bir nesneydi. Gerçek veri dosyadan veya ağdan gelir ve JSON.parse çağrısından çıkar. O çağrının dönüş değeri hangi tiptedir?

Yanıt, tip sisteminin iki uç noktasını tanıtır. any tipi “her şey olabilir, denetleme” der; unknown tipi “her şey olabilir, o yüzden önce sına” der. İkisinin arasındaki fark, kaydın güvenliğiyle ilgili en önemli kararlardan biridir. Dersin sonunda üçüncü bir uç gelecek: hiçbir değeri olmayan never tipi.

any: Denetimin Kapatılması

any, tip denetleyicisine bir değer hakkında hiçbir şey iddia etmemesini söyler:

const ham: any = JSON.parse('{"kimlik":"s-01","deger":"23.0"}');

console.log(ham.deger.toFixed(1));
console.log(ham.olmayan.alan);
const sayi: number = ham;

Bu dosya tip denetiminden hatasız geçer. Üç satırın üçü de hatalıdır: deger alanı dizgidir, olmayan diye bir alan yoktur ve ham bir sayı değildir. Derleyici hiçbirini bildirmez, çünkü any değerinin hangi alanlara sahip olduğu hakkında bir iddiası yoktur.

anyin iki yönlü davranışı vardır: any tipindeki bir değer her tipe atanabilir, her tip de anye atanabilir. Bu, tipin denetim ağından çıkarılması demektir. Bir alan any olduğunda, o alandan türeyen her ifade de denetimsiz kalır — denetimsizlik yayılır.

JSON.parse fonksiyonunun bildirilmiş dönüş tipi anydir. Bunun nedeni açık: dizginin içeriği ancak çalışma zamanında bilinir, derleyicinin söyleyecek bir şeyi yoktur. Sonuç, ilk derste görülen duruma benzer — tip denetimi susar, hata çalışma zamanına ertelenir.

Derleyici, tip yazılmadığında any çıkarmayı da reddedebilir:

function ortalama(olcumler) {
  return olcumler.length;
}
console.log(ortalama([1, 2, 3]));
c6.ts(1,19): error TS7006: Parameter 'olcumler' implicitly has an 'any' type.

Bu tanı noImplicitAny seçeneğinden gelir ve katı yapılandırmanın parçasıdır. Ayrımı görmek gerekir: örtük any bir eksikliktir, derleyici uyarır. Açık any bir karardır, derleyici susar. Kod tabanında any yazımlarını aramak, denetimin kapatıldığı yerleri aramak demektir.

unknown: Denetimin Ertelenmesi

unknown, any ile aynı değer kümesini kapsar — her değer unknown tipine atanabilir — ama ters yön kapalıdır:

const ham: unknown = JSON.parse('{"kimlik":"s-01","deger":"23.0"}');

console.log(ham.deger);
const sayi: number = ham;
c2.ts(3,13): error TS18046: 'ham' is of type 'unknown'.
c2.ts(4,7): error TS2322: Type 'unknown' is not assignable to type 'number'.

unknown tipindeki bir değerle hiçbir şey yapılamaz: alanına erişilemez, çağrılamaz, başka bir tipe atanamaz. Yapılabilecek tek şey, tipini daraltmaktır.

İki tipin ilişkisi bir sıralamayla anlatılabilir. Atanabilirlik yönünde unknown en üstte durur: her tip ona atanır, o hiçbir tipe atanmaz. Bu nedenle en üst tip (top type) denir. any ise bu sıralamanın dışındadır; her iki yöne de atanır ve tam bu yüzden bir güvence taşımaz.

Pratik kural: sistem sınırında unknown kullanılır. Dış veri unknown olarak alınır, sınanır, ancak sınamadan sonra modele girer.

Sınırda Doğrulama

Ölçüm kaydının dosyadan okunması bu kuralın uygulanmasıdır:

type Olcum = { kimlik: string; deger: number };

function oku(ham: string): Olcum | null {
  const cozulen: unknown = JSON.parse(ham);
  if (
    typeof cozulen === "object" &&
    cozulen !== null &&
    "kimlik" in cozulen &&
    typeof cozulen.kimlik === "string" &&
    "deger" in cozulen &&
    typeof cozulen.deger === "number"
  ) {
    return { kimlik: cozulen.kimlik, deger: cozulen.deger };
  }
  return null;
}

console.log(oku('{"kimlik":"s-01","deger":21.4}'));
console.log(oku('{"kimlik":"s-01","deger":"23.0"}'));
console.log(oku('42'));

Çıktı:

{ kimlik: 's-01', deger: 21.4 }
null
null

Koşulun her parçası bir adım daraltma yapar. typeof cozulen === "object" ifadesinden sonra derleyici değerin bir nesne olduğunu bilir; cozulen !== null ile null olasılığı elenir; "kimlik" in cozulen ile o alanın varlığı kanıtlanır; typeof sınamasıyla alanın tipi belirlenir. Koşulun içine girildiğinde derleyici cozulen.kimlik ifadesinin string olduğunu kanıtlamıştır — programcının sözüne değil, koddaki sınamalara dayanarak.

Bu, kursun eksenidir: tip sistemi bir kanıt katmanıdır ve sınamalar kanıtın adımlarıdır. Daraltmanın kuralları ile daha az tekrar eden yazım biçimleri Tip Daraltma dersinde ele alınacaktır.

Aynı işi as Olcum yazarak yapmak da mümkündü ve ilk derste görüldüğü gibi hatalı davranırdı. Fark şurada: as yazımında güvence programcının iddiasından, yukarıdaki kodda ise gerçekten çalışan sınamalardan gelir.

never: Boş Tip

never, hiçbir değeri olmayan tiptir. Boş kümedir. İki yerde ortaya çıkar.

Birincisi, hiçbir zaman normal yoldan dönmeyen fonksiyonların dönüş tipi:

function dur(ileti: string): never {
  throw new Error(ileti);
}

const her: string = dur("kayit okunamadi");
const hicbir: never = "s-01";
console.log(her, hicbir);
c5.ts(6,7): error TS2322: Type '"s-01"' is not assignable to type 'never'.

Beşinci satır hata vermez, altıncı verir. Bunun nedeni neverin atanabilirlik sıralamasındaki yeridir: never her tipe atanabilir, hiçbir tip nevere atanamaz. Boş kümenin her kümenin alt kümesi olması gibi. Bu yüzden never en alt tip (bottom type) diye anılır. dur fonksiyonu hiçbir değer döndürmediği için, döndürdüğü değerin string olması gerektiğini söylemek boş bir iddiadır ve derleyici buna izin verir.

İkinci ortaya çıkışı daha yararlıdır: tükenmişlik denetimi (exhaustiveness checking). Ölçüm kaydının durumları bir birleşimle tanımlansın:

type Durum = "gecerli" | "suphe" | "hatali";

function etiket(durum: Durum): string {
  switch (durum) {
    case "gecerli":
      return "olcum gecerli";
    case "suphe":
      return "olcum supheli";
    default: {
      const elealinmayan: never = durum;
      return elealinmayan;
    }
  }
}

console.log(etiket("gecerli"));
c4.ts(10,13): error TS2322: Type '"hatali"' is not assignable to type 'never'.

Tanı, ele alınmayan durumun adını doğrudan söyler. Mekanizma şudur: iki case dalından sonra derleyici, default dalına yalnızca "hatali" değerinin ulaşabileceğini bilir. never tipine atama denemesi, kalan kümenin boş olup olmadığını sınar. Küme boş değilse tanı gelir ve içindeki değer tanının metnine yazılır.

Bu kalıbın değeri, birleşime yeni bir durum eklendiğinde ortaya çıkar. Durum tipine dördüncü bir değer eklenirse, o değeri ele almayan her switch bloğu derleme anında hata verir. Tip sistemi burada bir bakım aracına dönüşür: modelin değişmesi, modeli kullanan tüm kodun gözden geçirilmesini zorunlu kılar.

Üç Tipin Yeri

Üçünün ilişkisi tek bir tabloda toplanabilir:

Tip Ona atanabilenler Ona atananın gidebildiği yerler Kullanım yeri
any Her tip Her tip Kademeli geçişte geçici
unknown Her tip Yok (daraltma gerekir) Sistem sınırı
never Yok Her tip Tükenmişlik denetimi, dönmeyen fonksiyon

Tablodaki ilk satır anyin neden bir tip değil bir kapı olduğunu gösterir: her iki sütunu da dolu olan tek satırdır ve bu, hiçbir kısıt getirmediği anlamına gelir. unknown ile never ise birbirinin karşıtıdır — biri her şeyi kapsar ve hiçbir şeye izin vermez, diğeri hiçbir şeyi kapsamaz ve her yere gider.

any tamamen yasaklanmaz. JavaScript ile Birlikte Çalışma dersinde görüleceği gibi, tip bilgisi olmayan bir kod tabanına kademeli geçişte geçici olarak gereklidir. Kural şudur: any bir geçiş işaretidir, bir çözüm değil; kaldığı yer belgelenir ve daraltılır.

Özet

  • any, tip denetimini kapatır; her iki yönde atanabilir olduğu için hiçbir güvence taşımaz ve denetimsizliği yayar.
  • Örtük any bir eksikliktir ve noImplicitAny seçeneğiyle bildirilir; açık any bir karardır.
  • unknown en üst tiptir: her değer ona atanır, o hiçbir tipe atanmaz; kullanılabilmesi için daraltılması gerekir.
  • Sistem sınırından gelen veri unknown olarak alınır ve alan alan sınanarak modele girer; as yazımı bu sınamanın yerine geçmez.
  • never en alt tiptir: hiçbir değeri yoktur, her tipe atanır; switch bloklarında tükenmişlik denetimi için kullanılır.

Sonraki Adım

Buraya kadar tipler elle yazıldı. Oysa yukarıdaki örneklerin çoğunda derleyici, yazılmamış tipleri kendiliğinden biliyordu: oku fonksiyonunun içindeki daraltma sonrası tipler, nesne sabitinin alan tipleri, dizi elemanlarının tipi. Sonraki ders bu bilgiyi nereden aldığını — tip çıkarımının kurallarını ve sınırlarını — ele alacak.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat