İçeriğe geç
academia.sh

Ders 21 / 23

JavaScript ile Birlikte Çalışma

JavaScript dosyalarının projeye alınması ve denetlenmesi, açıklamalarla tipleme, dosya düzeyinde denetim yönergeleri ve kademeli geçiş stratejisi.

İçindekiler

Önceki ders, tipsiz bir kütüphaneyi dışarıdan tiplemenin yolunu kurdu. Projenin kendi JavaScript dosyaları başka bir sorundur: var olan bir kod tabanı bir gecede dönüştürülemez.

TypeScript bu geçişi destekleyecek biçimde tasarlanmıştır. Her JavaScript dosyası aynı zamanda geçerli bir TypeScript girdisidir; denetim düzeyi ise proje ve dosya bazında ayarlanabilir. Bu ders geçişin araçlarını ve sırasını ele alır.

JavaScript Dosyalarını Projeye Almak

İki ayrı seçenek vardır ve karıştırılmaları sık görülür.

allowJs, JavaScript dosyalarının projeye alınmasını sağlar: derleyici onları okur, dışa aktardıkları adları bilir ve TypeScript dosyalarından içe aktarılmalarına izin verir. checkJs, bu dosyaların tip denetiminden geçmesini sağlar.

{
  "compilerOptions": {
    "target": "es2022",
    "module": "nodenext",
    "moduleResolution": "nodenext",
    "strict": true,
    "allowJs": true,
    "checkJs": false,
    "noEmit": true
  },
  "include": ["src"]
}

Proje kökünde { "name": "olcum-gecis", "type": "module", "version": "1.0.0" } içeriğinde bir package.json bulunsun. src/eski.js, geçiş öncesi koddur:

export function ortalama(kayitlar) {
  let toplam = 0;
  for (const k of kayitlar) {
    toplam += k.deger;
  }
  return toplam / kayitlar.length;
}

src/yeni.ts onu kullanır:

import { ortalama } from "./eski.js";

const kayitlar = [{ deger: 21.4 }, { deger: 22.1 }];
const sonuc: number = ortalama(kayitlar);
console.log(sonuc.toFixed(1));

Bu yapılandırmayla derleme hatasız geçer. Ancak güvence yoktur: ortalama fonksiyonunun parametresi ve dönüş değeri any sayılır, dolayısıyla sonuc bildirimi hiçbir şey sınamaz.

"checkJs": true yapıldığında:

src/eski.js(1,26): error TS7006: Parameter 'kayitlar' implicitly has an 'any' type.

Katı yapılandırma artık JavaScript dosyasına da uygulanır. Büyük bir kod tabanında bu adım yüzlerce tanı üretir; bu nedenle geçiş genellikle dosya dosya yapılır.

Açıklamalarla Tipleme

JavaScript dosyaları, sözdizimlerini değiştirmeden tiplenebilir. Derleyici, belirli bir biçimdeki açıklama bloklarını tip bildirimi olarak okur:

/**
 * @typedef {object} Olcum
 * @property {string} kimlik
 * @property {number} deger
 */

/**
 * @param {readonly Olcum[]} kayitlar
 * @returns {number}
 */
export function ortalama(kayitlar) {
  let toplam = 0;
  for (const k of kayitlar) {
    toplam += k.deger;
  }
  return toplam / kayitlar.length;
}

Bu dosya "checkJs": true ile hatasız denetlenir ve dışa aktardığı fonksiyon artık tiplenmiştir. Kullanan TypeScript dosyası:

import { ortalama } from "./eski.js";

const kayitlar = [
  { kimlik: "s-01", deger: 21.4 },
  { kimlik: "s-02", deger: 22.1 },
];
const sonuc: number = ortalama(kayitlar);
console.log(sonuc.toFixed(1));

ortalama([{ kimlik: "s-03", deger: "23.0" }]);
src/yeni.ts(10,29): error TS2322: Type 'string' is not assignable to type 'number'.

Tanı, JavaScript dosyasındaki açıklamadan gelen sözleşmenin gerçekten uygulandığını gösterir. @typedef, @param ve @returns yönergeleri kursta kurulan tip yazımlarının açıklama içindeki karşılığıdır; birleşim, dizi ve genellik yazımları da desteklenir.

Bu yöntemin bedeli okunabilirliktir: aynı bilgi daha uzun yazılır ve gövdeden ayrı durur. Kazancı, dosyanın hâlâ sıradan bir JavaScript dosyası olmasıdır — derleme adımı gerektirmeden çalışır. Derleme adımı bulunmayan projelerde ya da geçişin ilk aşamasında uygun bir ara çözümdür.

Dosya Düzeyinde Denetim Yönergeleri

Denetim, dosyanın başına konan bir açıklamayla da açılıp kapatılabilir. "checkJs": false iken bir dosyaya // @ts-check yazmak, yalnızca o dosyayı denetime alır:

// @ts-check

/**
 * @typedef {object} Olcum
 * @property {string} kimlik
 * @property {number} deger
 */

/**
 * @param {readonly Olcum[]} kayitlar
 * @returns {number}
 */
export function ortalama(kayitlar) {
  let toplam = 0;
  for (const k of kayitlar) {
    toplam += k.kimlik;
  }
  return toplam / kayitlar.length;
}
src/eski.js(16,5): error TS2322: Type 'string' is not assignable to type 'number'.

Ters yönergesi // @ts-nochecktir ve "checkJs": true iken bir dosyayı denetim dışında bırakır.

İki yönergenin kullanım yeri farklıdır. // @ts-check, geçişin başında az sayıda dosyayı denetime almak içindir — proje ayarı kapalı, dosyalar tek tek açılır. // @ts-nocheck, geçişin sonunda kalan birkaç dosyayı geçici olarak dışarıda bırakmak içindir — proje ayarı açık, dosyalar tek tek muaf tutulur. İkinci düzen yeğlenir: varsayılan güvenli, muafiyet görünürdür.

Tek Satırlık Muafiyet

Bazen bir dosyanın tamamı değil, tek bir satır sorunludur. İki yönerge vardır ve aralarındaki fark önemlidir.

// @ts-ignore, sonraki satırdaki tüm tanıları bastırır ve bastıracak bir tanı olmasa da sessiz kalır. // @ts-expect-error ise sonraki satırda bir tanı beklediğini söyler; beklenen tanı gelmezse kendisi tanı üretir:

import { ortalama } from "./eski.js";

const kayitlar = [
  { kimlik: "s-01", deger: 21.4 },
  { kimlik: "s-02", deger: 22.1 },
];
const sonuc: number = ortalama(kayitlar);
console.log(sonuc.toFixed(1));

// @ts-expect-error dizgi deger kabul edilmez
ortalama([{ kimlik: "s-03", deger: "23.0" }]);

// @ts-expect-error bu satir aslinda gecerli
ortalama([{ kimlik: "s-04", deger: 24.0 }]);
src/yeni.ts(13,1): error TS2578: Unused '@ts-expect-error' directive.

Onuncu satırdaki yönerge doğrudur ve tanı üretmez; on üçüncü satırdaki yönerge gereksizdir ve bildirilir.

Bu davranış, // @ts-expect-error yönergesini // @ts-ignore karşısında üstün kılar. Bastırılan bir hata sonradan düzeltildiğinde — kütüphane güncellendiğinde, tip tanımı iyileştirildiğinde — @ts-ignore sessizce kalır ve kimse fark etmez. @ts-expect-error ise “artık gerekli değilim” der. Muafiyetler böylece kendiliğinden temizlenir.

Her iki yönergenin de yanına gerekçe yazılır; yukarıdaki örnekte olduğu gibi yönerge metninin devamı açıklama olarak kabul edilir.

Kademeli Geçiş Sırası

Toplanan araçlar bir sıraya konabilir. Her adım, önceki adımın sağladığı güvenceyi korur:

  1. allowJs açılır, checkJs kapalı kalır. JavaScript dosyaları projeye girer; hiçbir yeni tanı gelmez. Yeni yazılan kod TypeScript olur.
  2. Sık kullanılan modüllerin sözleşmeleri yazılır. Ya .d.ts dosyasıyla ya da açıklamalarla. En çok içe aktarılan modüller önce ele alınır; her biri, kendisini kullanan tüm dosyalara güvence yayar.
  3. Dosyalar tek tek // @ts-check ile denetime alınır. Çıkan tanılar düzeltilir. Düzeltilemeyenler // @ts-expect-error ile gerekçelendirilir.
  4. checkJs açılır, kalan dosyalar // @ts-nocheck ile muaf tutulur. Varsayılan artık güvenli taraftadır.
  5. Dosyalar .ts uzantısına taşınır ve açıklamadaki tipler sözdizime çevrilir.
  6. Şemsiye dışındaki katılık bayrakları teker teker açılır. Derleyici Yapılandırması dersindeki noUncheckedIndexedAccess ve exactOptionalPropertyTypes bu aşamada gelir.

Sıranın ilkesi, her adımda kırmızının sıfırda tutulmasıdır: derleme her zaman temiz geçmeli, yeni tanılar biriktirilmemelidir. Aksi hâlde tanı listesi bir gürültüye dönüşür ve gerçek hatalar arasında kaybolur.

Bir noktada any kullanımı kaçınılmazdır. Kaçış kapıları dersindeki kural burada uygulanır: any bir geçiş işaretidir. Nerede kaldığı belgelenir ve geçişin sonraki turlarında daraltılır.

Özet

  • allowJs JavaScript dosyalarını projeye alır, checkJs onları tip denetimine sokar; ikisi ayrı kararlardır.
  • Açıklama yazımıyla (@typedef, @param, @returns) JavaScript dosyaları sözdizimleri değişmeden tiplenir; sözleşme TypeScript tarafında da uygulanır.
  • // @ts-check ve // @ts-nocheck denetimi dosya düzeyinde açar ve kapatır; muafiyetin görünür olduğu düzen yeğlenir.
  • // @ts-expect-error, beklenen tanı gelmediğinde TS2578 üretir ve gereksiz muafiyetlerin temizlenmesini sağlar; // @ts-ignore bunu yapmaz.
  • Kademeli geçiş, her adımda derlemeyi temiz tutarak ilerler: dosyaları almak, sözleşmeleri yazmak, denetimi açmak, uzantıyı taşımak, katılığı artırmak.

Sonraki Adım

Bu dersteki içe aktarma satırı ./eski.js yazıyordu ve uzantı zorunluydu. Aynı yazım, kaynak bir TypeScript dosyası olduğunda da değişmez — bu, modül çözümlemenin kurallarından biridir ve ilk bakışta şaşırtıcıdır. Sonraki ders derleyicinin bir modül adını nasıl bir dosyaya çevirdiğini, yol eşlemeyi ve çözümleme ayarlarının çıktı üzerindeki etkisini 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