Blok 6 · Ders 39
TypeScript: tiplerle güvenli kod
Değişkenlere ve fonksiyonlara tip vermek, type ve interface, birleşim tipleri ve hataları kod çalışmadan yakalamak.
Bu dersin sonunda
- Bir JavaScript dosyasını TypeScript'e çevirip değişkenlere, parametrelere ve dönüş değerlerine tip yazabilir, gerisini tip çıkarımına bırakabilirsin
typeveinterfaceile obje ve dizi şekilleri tanımlayıp isteğe bağlı alanları (?) güvenle kullanabilirsin- Birleşim tipleriyle izin verilen değerleri (
"ust" | "orta") sınırlayıptypeof,inve ayırt edici alanla daraltabilirsin - Dışarıdan gelen veriyi
anyyerineunknownolarak alıp denetleyerek tipli bir objeye çevirebilirsin .tsdosyasınınodeile çalıştırıpnpx tsc --noEmitile denetleyebilir,tsconfig.json'ın temel ayarlarını açıklayabilirsinTS2322,TS2345,TS2339,TS7006veTS18048mesajlarında yeri, verilen ve beklenen tipi bulup hatayı düzeltebilirsin
Bu sayfada
- Neden tip: hatayı çalıştırmadan görmek
- TypeScript'i projeye kurmak
- Temel tipler
- Fonksiyonlara tip vermek
- type ve interface: objenin şekli
- Dizi ve obje tipleri
- Birleşim tipleri ve daraltma
- any neden kötü, unknown neden iyi
- Node'da .ts çalıştırmak ve tsc ile denetlemek
- Tip hata mesajlarını okumak
- Sık hatalar
- Görevler
- Kendini sına
- Kayıt noktası
Ders 38'in sonunda API'n çalışıyordu, ama yolda karşılaştığın hataların çoğu kod çalışırken ortaya çıktı: metin olarak gelen sayılar, küçük harfe dönen alan adları, null gelen sütunlar. Bu derste JavaScript'e tip ekleyen TypeScript'i öğreniyorsun. Kodu yazarken her değerin ne olabileceğini söyleyeceksin; TypeScript da program daha çalışmadan bu sözü bozan satırları gösterecek. Dersin sonunda .ts dosyalarını Node ile çalıştırabilecek, tsc ile denetleyebilecek ve tip hata mesajlarını okuyup düzeltebileceksin.
Neden tip: hatayı çalıştırmadan görmek
Isınmadaki dört hatanın ortak yanı ne? Hiçbiri kodu yazdığın anda görünmedi. Kod çalıştı, bir gün belli bir veriyle karşılaştı ve ya yanlış sonuç verdi ya da çöktü. Bir hatayı ne zaman fark ettiğin, onu ne kadar pahalıya ödediğini belirler.
Bu derste yeni bir klasörde çalışacaksın. Terminalde cd C:\kod ile kod klasörüne geç, mkdir tipler ile klasörü oluştur ve code tipler ile VS Code'da aç (Ders 6'daki gibi). Yeni pencerede terminali aç ve seri.js adında bir dosya oluştur:
const jinx = { isim: "Jinx", seri: 0 } for (let i = 1; i <= 5; i++) { jinx.seri = jinx.seri + 1 if (jinx.seri === 5) { console.log(jinx.isim.toUppercase() + ": PENTAKILL!") } else { console.log(jinx.isim + " seri: " + jinx.seri) }}Jinx seri: 1Jinx seri: 2Jinx seri: 3Jinx seri: 4C:\kod\tipler\seri.js:6 console.log(jinx.isim.toUppercase() + ": PENTAKILL!") ^ TypeError: jinx.isim.toUppercase is not a function at Object.<anonymous> (C:\kod\tipler\seri.js:6:31) ... Node.js v24.20.0Program dört turu sorunsuz geçti, beşincide çöktü: toUpperCase yerine toUppercase yazılmış (küçük c). Hata 6. satırda, dosyayı yazdığın andan beri vardı. Ama JavaScript bir satırı ancak çalıştırırken okur; o satıra da yalnız seri 5'e ulaşınca gelinir. Pentakill nadir olur: böyle bir kod haftalarca çalışıp ilk pentakill'de bir oyuncunun önünde patlayabilir.
Şimdi VS Code'un dosya listesinde seri.js'e sağ tıkla, Rename'i seç ve adını seri.ts yap. İçeriğe dokunma. .ts, TypeScript dosyalarının uzantısıdır. VS Code TypeScript'i kendi içinde taşır; uzantıyı değiştirdiğin anda dosyayı denetlemeye başlar:
const jinx = { isim: "Jinx", seri: 0 } for (let i = 1; i <= 5; i++) { jinx.seri = jinx.seri + 1 if (jinx.seri === 5) { console.log(jinx.isim.toUppercase() + ": PENTAKILL!") } else { console.log(jinx.isim + " seri: " + jinx.seri) }}seri.ts 1 Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'? ts(2551) [Ln 6, Col 31]toUppercase'in altında kırmızı dalgalı bir çizgi var. Alttaki PROBLEMS sekmesi aynı hatayı yazıyla listeler: mesaj, hata kodu ts(2551) ve yeri (6. satır, 31. sütun). VS Code mesajı tek satırda yazar; burada sığsın diye ikiye böldük.
Program hiç çalışmadı, ama hata ortada. Mesaj İngilizce: Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'? Yani "string tipinde toUppercase diye bir alan yok; toUpperCase'i mi demek istedin?" Property, Ders 4'te öğrendiğin alan demek; tip mesajlarında metotlar da bu sözcükle anılır. Fareyi kırmızı çizginin üstüne getirirsen aynı mesaj küçük bir kutuda da görünür.
TypeScript bunu nereden bildi? isim alanına "Jinx" koydun; demek ki jinx.isim bir metin. Metinlerin hangi metotları olduğu da belli: listede toUpperCase var, toUppercase yok. TypeScript bunu kodu çalıştırmadan, yalnız okuyarak çıkardı. Tek bir tip bile yazmadığına dikkat et.
TypeScript her hatayı yakalamaz. Can hesabında - yerine + yazarsan iki satır da tip olarak doğrudur; mantık hatalarını yine sen yakalarsın. Bir de tipler yalnız senin kodunu bilir: internetten ya da veritabanından gelen verinin ne olduğu ancak çalışırken belli olur. Bunun çaresini dersin ilerisinde, unknown bölümünde göreceksin.
TypeScript'i projeye kurmak
VS Code'un denetimi yalnız açık dosyalara bakar ve VS Code'un içindeki TypeScript sürümüyle çalışır. Gerçek projelerde TypeScript'i projenin kendisine kurarsın: böylece bütün dosyaları terminalden tek komutla denetler, ayarları bir dosyada tutar, ekipteki herkesle ve sunucuyla aynı sürümü kullanırsın. Terminal C:\kod\tipler'deyken:
PS C:\kod\tipler> npm init -yWrote to C:\kod\tipler\package.json:...PS C:\kod\tipler> npm pkg set type=modulePS C:\kod\tipler> npm install -D typescript @types/node@24 added 4 packages, and audited 5 packages in 2s found 0 vulnerabilitiesPS C:\kod\tipler> npx tsc --versionVersion 7.0.2npm pkg set type=module: Ders 14'teki"type": "module"ayarı..tsdosyaların da ES modülü sayılır.-D: paketleripackage.json'dadependenciesyerinedevDependenciesaltına yazar. Uzun yazılışı--save-dev.typescript: TypeScript'in kendisi. İçindentsckomutu çıkar.@types/node@24: Node 24'ün tip tanımları.process,Buffergibi Node'a özgü adların tiplerini TypeScript buradan öğrenir.@24yazmazsan daha yeni bir Node sürümünün tanımları gelir.npx tsc --version:npxönce projeninnode_modulesklasörüne bakar; komut oradaysa onu çalıştırır. Ders 18'dekinpx serve'de paket projede yoktu ve npx onu indirmeden önce sormuştu; TypeScript ise artık projede kurulu, bir şey inmez. Bu ders TypeScript 7.0.2 ile denendi; sende daha yeni bir sürüm görünebilir.
TypeScript'e nasıl denetleyeceğini bir ayar dosyası söyler. Klasörde yeni bir dosya aç, adını tam olarak tsconfig.json koy ve yaz:
{ "compilerOptions": { "target": "esnext", "module": "nodenext", "types": ["node"], "strict": true, "noEmit": true, "skipLibCheck": true }}"compilerOptions": bütün ayarlar bu objenin içinde. Adındaki compiler (derleyici) sözcüğünü birazdan açıklıyoruz."target": "esnext"ve"module": "nodenext": en yeni JavaScript özelliklerini tanı, dosyaları Node'un modül kurallarıyla oku (import,export,"type": "module")."types": ["node"]: az önce kurduğun Node tiplerini kullan. Yazmazsanprocessgibi adları tanımaz."strict": true: en sıkı denetim. Bu derste göreceğin "tipi belirsiz parametre" ve "undefinedolabilir" hatalarını açan ayar budur. TypeScript 6'dan beri zaten varsayılan, ama açıkça yazmak dosyayı okuyan herkese niyetini söyler."noEmit": true: "yalnız denetle, dosya üretme".tscistersen her.ts'nin yanına bir.jsyazabilir; bize gerekmiyor, çünkü Node.ts'yi doğrudan çalıştırıyor. Komutta da--noEmityazacağız; ayar dosyasında olduğu için şart değil, ama komutu okuyan herkes ne yaptığını hemen anlasın."skipLibCheck": true:node_modulesiçindeki hazır tip dosyalarını yeniden denetleme; zaman kazandırır.
Şimdi bütün projeyi denetle:
PS C:\kod\tipler> npx tsc --noEmitseri.ts:6:31 - error TS2551: Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'? 6 console.log(jinx.isim.toUppercase() + ": PENTAKILL!") ~~~~~~~~~~~ node_modules/@typescript/typescript-win32-x64/lib/lib.es5.d.ts:506:5 - 'toUpperCase' is declared here. 506 toUpperCase(): string; ~~~~~~~~~~~~~~~~~~~~~~ Found 1 error in seri.ts:6VS Code'daki hatanın aynısı, bu kez terminalde. İlk satır yeri (seri.ts:6:31: dosya, satır, sütun), hata kodunu (TS2551) ve mesajı verir. Altında satırın kopyası durur; ~~~ işaretleri sorunlu kısmın altını çizer. Girintili ek satır, önerilen toUpperCase'in tanımlandığı yeri gösteriyor: TypeScript'in kendi tip dosyası. Bu tür ek satırları şimdilik geçebilirsin. Mesajları nasıl okuyacağını dersin sonunda ayrıntılı göreceksin.
6. satırı düzelt (toUpperCase, büyük C) ve iki komutu sırayla çalıştır:
const jinx = { isim: "Jinx", seri: 0 } for (let i = 1; i <= 5; i++) { jinx.seri = jinx.seri + 1 if (jinx.seri === 5) { console.log(jinx.isim.toUpperCase() + ": PENTAKILL!") } else { console.log(jinx.isim + " seri: " + jinx.seri) }}PS C:\kod\tipler> npx tsc --noEmitPS C:\kod\tipler> node seri.tsJinx seri: 1Jinx seri: 2Jinx seri: 3Jinx seri: 4JINX: PENTAKILL!npx tsc --noEmit hiçbir şey yazmadı: tsc'de sessizlik "hata yok" demek. node seri.ts ise dosyayı çalıştırdı.
Bundan sonra iş akışın hep bu: önce npx tsc --noEmit ile denetle, sonra node dosya.ts ile çalıştır. Node'un tipleri nasıl ele aldığını dersin ilerisinde göreceksin; şimdilik şunu bil: Node tipleri denetlemez. Tipi hatalı bir dosyayı da çalıştırır.
Temel tipler
Bir değişkenin tipini, adından sonra iki nokta koyup yazarsın. temel.ts dosyasını oluştur:
let isim: string = "Ahri"let hp: number = 100let canli: boolean = true hp = hp - 30console.log(isim, hp, canli)Ahri 70 trueisim: string, "isim bir metin olacak" demek. Bu eklere tip notu denir. Temel tipler, Ders 1'den beri kullandığın değerlerin adlarıdır; en sık ilk üçünü yazarsın:
| Tip | Ne tutar | Örnek değerler |
|---|---|---|
string | metin | "Ahri", "" |
number | her sayı: tam, ondalıklı, eksi | 100, 3.5, -20 |
boolean | doğru ya da yanlış | true, false |
undefined | henüz bir değer yok (Ders 3) | undefined |
null | bilerek boş bırakılmış (Ders 12) | null |
Tip adları küçük harfle yazılır: string, number, boolean. Ders 33'te Postgres sütunlarına veri tipi vermiştin; fikir aynı, kutular farklı. Bir fark var: Postgres'te integer ile numeric ayrıydı, TypeScript'te tam sayı da ondalıklı sayı da number.
error TS2322: Type 'string' is not assignable to type 'number'.Ne zaman çıkar? Bir tipe söz verdiğin kutuya başka tipte bir değer koyunca. Dene: temel.ts'nin 5. satırını hp = "yetmiş" yap.
let isim: string = "Ahri"let hp: number = 100let canli: boolean = true hp = "yetmiş"console.log(isim, hp, canli)Ahri yetmiş trueNode itiraz etmeden çalıştırdı. Can artık bir metin ve bunu ilk fark eden, bir sonraki hp - 10 hesabında NaN gören kişi olacak. tsc ise satırı hemen gösterir:
PS C:\kod\tipler> npx tsc --noEmittemel.ts:5:1 - error TS2322: Type 'string' is not assignable to type 'number'. 5 hp = "yetmiş" ~~ Found 1 error in temel.ts:5Type 'string' is not assignable to type 'number': "string tipindeki değer, number tipindeki yere atanamaz". İlk tip senin verdiğin değerin tipi, ikincisi oranın beklediği.
Nasıl düzelir? Hangisi yanlışsa onu düzelt: değer mi (hp = 70), söz mü? Bir değer gerçekten hem sayı hem metin olabiliyorsa tipi genişletirsin; bunu birleşim tiplerinde göreceksin. Şimdilik 5. satırı hp = hp - 30'a geri al.
Tip çıkarımı: her yere tip yazmazsın
Her değişkene tip yazmak yorucu olurdu ve çoğu zaman gerek de yok. cikarim.ts'yi hiç tip notu kullanmadan yaz:
let altin = 300const koridor = "orta" altin = altin + 150altin = "bin"console.log(altin, koridor)bin ortaPS C:\kod\tipler> npx tsc --noEmitcikarim.ts:5:1 - error TS2322: Type 'string' is not assignable to type 'number'. 5 altin = "bin" ~~~~~ Found 1 error in cikarim.ts:5Dosyada tek bir tip notu yok, ama TypeScript altin'ın number olduğunu biliyor: ilk değeri 300'dü. Buna tip çıkarımı denir. VS Code'da fareyi 1. satırdaki altin'ın üstüne getir: küçük kutuda let altin: number yazar. koridor'un üstüne getirince const koridor: "orta" görürsün. const asla değişmeyeceği için tipi "herhangi bir metin" değil, tam olarak "orta"; bunun ne işe yaradığını birleşim tiplerinde göreceksin. 5. satırı sil, dosya temizlensin.
Peki ne zaman tip yazarsın?
- Fonksiyon parametrelerine her zaman. TypeScript bir parametreye hangi değerin geleceğini bilemez. Bir sonraki bölümün konusu bu.
- Değeri sonradan verilecek değişkene:
let kazanan: stringyazıp değeri ileride koyacaksan. - İzin verilen değerleri daraltmak istediğinde: "bu alan yalnız şu beş koridordan biri olabilir" gibi. Birleşim tipleri bölümünde.
- Geri kalan her yerde (
let altin = 300gibi) işi TypeScript'e bırak. Gereksiz tip notları kodu yalnız kalabalıklaştırır.
Fonksiyonlara tip vermek
Fonksiyonlar TypeScript'in en çok işe yaradığı yerdir. Bir fonksiyonu yazdığın an ile çağırdığın an arasında günler geçebilir; çağıran kişi başkası bile olabilir. Parametrelerin ve dönüş değerinin tipi, fonksiyonun kullananlara verdiği sözdür. hasar.ts:
function hasarVer(hp: number, hasar: number): number { return Math.max(hp - hasar, 0)} function iyiles(hp: number, miktar: number): number { return hp + miktar} console.log(hasarVer(100, 30))console.log(hasarVer(20, 50))console.log(iyiles(70, 20))70090Kalıp şu: her parametrenin adından sonra tipi (hp: number), parantezden sonra da dönüş tipi (): number). hasarVer "iki sayı alırım, bir sayı döndürürüm" diyor. Math.max(…, 0) (Ders 9) canın eksiye düşmesini engelliyor; ikinci satırdaki 0 bu yüzden.
error TS7006: Parameter 'hp' implicitly has an 'any' type.Ne zaman çıkar? Bir parametreye tip yazmayınca. Dene: hasar.ts'nin 5. satırındaki bütün tipleri sil.
function iyiles(hp, miktar) { return hp + miktar}PS C:\kod\tipler> npx tsc --noEmithasar.ts:5:17 - error TS7006: Parameter 'hp' implicitly has an 'any' type. 5 function iyiles(hp, miktar) { ~~ hasar.ts:5:21 - error TS7006: Parameter 'miktar' implicitly has an 'any' type. 5 function iyiles(hp, miktar) { ~~~~~~ Found 2 errors in the same file, starting at: hasar.ts:5Parameter 'hp' implicitly has an 'any' type: "hp parametresinin tipi örtük olarak any". TypeScript bu fonksiyona ne geleceğini kestiremedi ve tipi belirsiz kaldı. any "her şey olabilir, denetleme" demek; strict ayarı onun sessizce araya girmesine izin vermiyor. Program yine çalışır, node hasar.ts aynı üç satırı yazar; ama iyiles artık hiçbir şeyi denetlemiyor. any'nin neden tehlikeli olduğu ayrı bir bölümde.
Nasıl düzelir? Parametrelere tiplerini geri yaz: function iyiles(hp: number, miktar: number): number.
error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.Ne zaman çıkar? Bir fonksiyonu yanlış tipte bir argümanla çağırınca. Değer çoğu zaman başka bir yerden gelir: bir formdan, bir dosyadan, bir API'den. Dene: tipleri geri yazdıktan sonra hasar.ts'nin sonuna, bir satır boşluk bırakıp şunları ekle:
const iksir = "20"console.log(iyiles(70, iksir))Node'a göre sorun yok: dördüncü çıktı satırına 90 yerine 7020 yazar. + metin görünce toplamak yerine yapıştırdı (Ders 1); ısınmadaki "2" + "2"'nin aynısı. tsc ise çağrıyı yakalar:
PS C:\kod\tipler> npx tsc --noEmithasar.ts:14:24 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. 14 console.log(iyiles(70, iksir)) ~~~~~ Found 1 error in hasar.ts:14"string tipindeki argüman, number tipindeki parametreye verilemez". TS2322'nin fonksiyon çağrısındaki kardeşi: yine önce verdiğin tip, sonra beklenen.
Nasıl düzelir? Değeri kaynağında doğru tipe çevir: const iksir = 20, ya da metin başka bir yerden geliyorsa Number(iksir) (Ders 9). Sonra eklediğin iki satırı sil.
Argümanların sayısı da denetlenir. 12. satıra console.log(hasarVer(100)) yazıp denetlersen:
PS C:\kod\tipler> npx tsc --noEmithasar.ts:12:13 - error TS2554: Expected 2 arguments, but got 1. 12 console.log(hasarVer(100)) ~~~~~~~~ hasar.ts:1:31 - An argument for 'hasar' was not provided. 1 function hasarVer(hp: number, hasar: number): number { ~~~~~~~~~~~~~ Found 1 error in hasar.ts:12"2 argüman bekleniyordu, 1 geldi." Ek satır hangi parametrenin boş kaldığını da söylüyor: hasar. Node bu satırda NaN yazardı: hasar undefined kalır ve 100 - undefined bir sayı değildir. Satırı sil.
Dönüş tipi bir sözdür
durum.ts:
function durum(hp: number): string { if (hp > 0) { return "hayatta" } else if (hp === 0) { return "öldü" }} console.log(durum(50))console.log(durum(-10))hayattaundefinedPS C:\kod\tipler> npx tsc --noEmitdurum.ts:1:29 - error TS2366: Function lacks ending return statement and return type does not include 'undefined'. 1 function durum(hp: number): string { ~~~~~~ Found 1 error in durum.ts:1: string, "bu fonksiyon her zaman metin döndürür" sözü. Ama can eksiyse iki koşul da tutmaz ve fonksiyon return'e uğramadan biter, yani undefined döner (Ders 6). Mesaj tam bunu söylüyor: "fonksiyonun sonunda return yok ve dönüş tipi undefined içermiyor". Sınır değerini senin yerine TypeScript düşündü. Sona bir return ekle:
function durum(hp: number): string { if (hp > 0) { return "hayatta" } else if (hp === 0) { return "öldü" } return "geçersiz can"} console.log(durum(50))console.log(durum(-10))hayattageçersiz canHiçbir şey döndürmeyen fonksiyon ve ok fonksiyonu
kritik.ts:
const kritikVurus = (hasar: number, carpan: number = 2): number => hasar * carpan function duyur(mesaj: string): void { console.log("[Duyuru] " + mesaj)} duyur("Kritik vuruş: " + kritikVurus(45))duyur("Süper kritik: " + kritikVurus(45, 3))[Duyuru] Kritik vuruş: 90[Duyuru] Süper kritik: 135- Ok fonksiyonunda (Ders 10) tipler aynı yerlere yazılır: parametrelerin yanına ve parantezden sonra.
carpan: number = 2: varsayılan değeri olan parametre. Burada: numberyazmasan da olurdu; TypeScript tipi2'den çıkarır. Çağıran bu argümanı vermeyebilir.void(boşluk): fonksiyon bir şey döndürmüyor.duyuryalnız ekrana yazıyor; sonucunu bir değişkene koymanın anlamı yok.
type ve interface: objenin şekli
Fonksiyona tek tek sayı vermek kolay. Peki Ders 4'teki gibi bütün bir şampiyon objesi gelecekse? Bir objenin tipi, hangi alanları olduğu ve her alanın tipidir. Bu şekli bir kez tanımlar, ona bir ad verirsin. sampiyon.ts:
type Sampiyon = { isim: string hp: number gold: number} const ahri: Sampiyon = { isim: "Ahri", hp: 100, gold: 300 } function durumYaz(s: Sampiyon): string { return s.isim + ": " + s.hp + " can, " + s.gold + " altın"} console.log(durumYaz(ahri))Ahri: 100 can, 300 altıntype Sampiyon = { … }: "Sampiyonadında bir tip tanımlıyorum:isimmetni,hpvegoldsayıları olan bir obje."typebir tipe ad verir.- Tip adları büyük harfle başlar, Ders 16'daki sınıf adları gibi (PascalCase). Değişkenin adı
ahri, tipininkiSampiyon. - Alanların arasına virgül koymadık: her alan kendi satırındaysa gerekmez. Tek satırda yazarsan
{ isim: string; hp: number }diye noktalı virgülle ayırırsın. const ahri: Sampiyon, "bu objeSampiyonşeklinde" sözü.durumYaz(s: Sampiyon)da "bana bu şekilde bir obje ver" diyor.
Şekle uymayan her obje yakalanır. sampiyon.ts'nin sonuna, bir satır boşluk bırakıp bilerek üç hatalı satır ekle:
const lux: Sampiyon = { isim: "Lux", hp: 90 }const jinx: Sampiyon = { isim: "Jinx", hp: 80, gold: 250, mana: 300 }console.log(ahri.mana)PS C:\kod\tipler> npx tsc --noEmitsampiyon.ts:15:7 - error TS2741: Property 'gold' is missing in type '{ isim: string; hp: number; }' but required in type 'Sampiyon'. 15 const lux: Sampiyon = { isim: "Lux", hp: 90 } ~~~ sampiyon.ts:4:5 - 'gold' is declared here. 4 gold: number ~~~~ sampiyon.ts:16:59 - error TS2353: Object literal may only specify known properties, and 'mana' does not exist in type 'Sampiyon'. 16 const jinx: Sampiyon = { isim: "Jinx", hp: 80, gold: 250, mana: 300 } ~~~~ sampiyon.ts:17:18 - error TS2339: Property 'mana' does not exist on type 'Sampiyon'. 17 console.log(ahri.mana) ~~~~ Found 3 errors in the same file, starting at: sampiyon.ts:15- TS2741, Property 'gold' is missing…: "
goldalanı eksik amaSampiyon'da zorunlu". Ek satır zorunluluğun nereden geldiğini gösteriyor: tipin 4. satırı. - TS2353, Object literal may only specify known properties…: "obje yalnız bilinen alanları içerebilir;
manaSampiyon'da yok". Fazla bir alan çoğu zaman yazım hatasıdır (goldyerineglod); TypeScript bu yüzden durdurur. - TS2339: aşağıdaki kart.
error TS2339: Property 'mana' does not exist on type 'Sampiyon'.Ne zaman çıkar? Bir objede, tipinde olmayan bir alanı okuyunca. JavaScript bu satırda hata vermez, undefined verir (Ders 4): node sampiyon.ts önce Ahri: 100 can, 300 altın, sonra undefined yazar. Yanlış yazılmış bir alan adı böylece sessizce programın içine yayılır.
Mesaj "Sampiyon tipinde mana diye bir alan yok" diyor. Okumaya çalıştığın ad tanımlı bir alana çok benziyorsa TypeScript tahmin de yürütür ve kod TS2551 olur: Did you mean…? Biraz aşağıda Ders 38'in kullaniciadi hatasında göreceksin.
Nasıl düzelir? Alanın adını tipteki adla aynı yaz. Alan gerçekten gerekiyorsa önce tipe ekle; objenin şekli tek bir yerde, tipte tanımlı olsun. Sonra üç hatalı satırı sil.
interface: aynı işin ikinci yolu
Obje şekli tanımlamanın ikinci yolu interface. esya.ts:
interface Esya { ad: string fiyat: number} const kilic: Esya = { ad: "Uzun Kılıç", fiyat: 350 }console.log(kilic.ad + " " + kilic.fiyat + " altın")Uzun Kılıç 350 altınYazımdaki tek fark: interface Esya { … }, arada = yok. Obje şekli için ikisi aynı işi görür. Farkları şunlar:
type | interface | |
|---|---|---|
| Obje şekli tanımlamak | Evet | Evet |
Objeden başka tiplere ad vermek (type Koridor = "ust" | "orta") | Evet | Hayır, yalnız obje |
| Aynı adla ikinci kez yazılırsa | Hata verir (TS2300 Duplicate identifier) | İki tanım birleşir |
Bu kursta type kullanacağız: hem objeler hem birleşimler için tek kalıp. Bazı ekipler obje şekillerinde interface'i tercih eder; iş ilanlarındaki projelerde ikisini de göreceksin, okuyabilmen yeter.
İsteğe bağlı alan: ?
Her oyuncunun bir takımı yok. Bir alanın hiç olmayabileceğini, adından sonra soru işareti koyarak söylersin. oyuncu.ts:
type Oyuncu = { kullaniciAdi: string rol: string takimAdi?: string} const arda: Oyuncu = { kullaniciAdi: "arda", rol: "orman", takimAdi: "Gece Kurtları" }const deniz: Oyuncu = { kullaniciAdi: "deniz", rol: "orta" } function kunye(o: Oyuncu): string { return o.kullaniciAdi + " [" + o.takimAdi.toLocaleUpperCase("tr") + "]"} console.log(kunye(arda))console.log(kunye(deniz))arda [GECE KURTLARI]file:///C:/kod/tipler/oyuncu.ts:11 return o.kullaniciAdi + " [" + o.takimAdi.toLocaleUpperCase("tr") + "]" ^ TypeError: Cannot read properties of undefined (reading 'toLocaleUpperCase') at kunye (file:///C:/kod/tipler/oyuncu.ts:11:47) ... Node.js v24.20.0deniz objesinde takimAdi hiç yok ve TypeScript buna itiraz etmedi, çünkü ? alanı isteğe bağlı yaptı. Ama kunye takım adının hep var olduğunu varsayıyor; Deniz'e gelince çöktü. Bu, ısınmadaki LEFT JOIN sorusunun kardeşi. tsc bunu çalıştırmadan söylerdi:
error TS18048: 'o.takimAdi' is possibly 'undefined'.Ne zaman çıkar? undefined olabilecek bir değeri denetlemeden kullanınca: isteğe bağlı bir alan, find'ın sonucu, verilmeyebilecek bir parametre.
PS C:\kod\tipler> npx tsc --noEmitoyuncu.ts:11:36 - error TS18048: 'o.takimAdi' is possibly 'undefined'. 11 return o.kullaniciAdi + " [" + o.takimAdi.toLocaleUpperCase("tr") + "]" ~~~~~~~~~~ Found 1 error in oyuncu.ts:11"o.takimAdi, undefined olabilir." takimAdi?: string aslında "string ya da undefined" demek. Sen bu ihtimali ele alana kadar TypeScript alanın metotlarını kullandırmaz.
Nasıl düzelir? Alan yoksa ne olacağına karar ver: Ders 12'deki ?? ile bir yedek değer (o.takimAdi ?? "takımsız"), ?. ile "varsa çağır" ya da if (o.takimAdi) ile önce denetle. Değerin sonuna ! koyup (o.takimAdi!) "kesin var" diyerek hatayı susturmak da mümkün; ama yanılıyorsan program yine çöker.
kunye'yi yedek değerle düzelt ve sona bir satır ekle:
type Oyuncu = { kullaniciAdi: string rol: string takimAdi?: string} const arda: Oyuncu = { kullaniciAdi: "arda", rol: "orman", takimAdi: "Gece Kurtları" }const deniz: Oyuncu = { kullaniciAdi: "deniz", rol: "orta" } function kunye(o: Oyuncu): string { const takim = o.takimAdi ?? "takımsız" return o.kullaniciAdi + " [" + takim.toLocaleUpperCase("tr") + "]"} console.log(kunye(arda))console.log(kunye(deniz))console.log(deniz)arda [GECE KURTLARI]deniz [TAKIMSIZ]{ kullaniciAdi: 'deniz', rol: 'orta' }Son satır isteğe bağlı alanın ne demek olduğunu gösteriyor: deniz objesinde takimAdi diye bir alan hiç yok. takim değişkenine tip yazmadık; ?? yüzünden hiçbir zaman undefined olamayacağını TypeScript kendisi çıkardı.
Isınmadaki ikinci soruyu hatırla: Ders 38'de takma ad tırnaksız yazıldığı için alanın adı kullaniciadi olmuştu ve kullaniciAdi'yi okuyan kod undefined almıştı. Aynı yanlış okumayı oyuncu.ts'nin 18. satırına yaz:
console.log(deniz.kullaniciadi)PS C:\kod\tipler> npx tsc --noEmitoyuncu.ts:18:19 - error TS2551: Property 'kullaniciadi' does not exist on type 'Oyuncu'. Did you mean 'kullaniciAdi'? 18 console.log(deniz.kullaniciadi) ~~~~~~~~~~~~ oyuncu.ts:2:5 - 'kullaniciAdi' is declared here. 2 kullaniciAdi: string ~~~~~~~~~~~~ Found 1 error in oyuncu.ts:18TS2339'un öneri getiren kardeşi TS2551: ad, tanımlı bir alana çok benzediği için "kullaniciAdi'yi mi demek istedin?" diye soruyor. Satırı sil.
Dizi ve obje tipleri
Bir dizinin tipi, elemanlarının tipi ve arkasında köşeli parantezdir: string[] "metinlerden oluşan dizi", Sampiyon[] "Sampiyon objelerinden oluşan dizi". takim.ts:
type Sampiyon = { isim: string hp: number koridor: string} const takim: Sampiyon[] = [ { isim: "Garen", hp: 620, koridor: "ust" }, { isim: "Ahri", hp: 0, koridor: "orta" }, { isim: "Jinx", hp: 340, koridor: "alt" },] const isimler: string[] = takim.map((s) => s.isim)const canlilar = takim.filter((s) => s.hp > 0) console.log(isimler)console.log(canlilar.length + " şampiyon ayakta")[ 'Garen', 'Ahri', 'Jinx' ]2 şampiyon ayaktaconst takim: Sampiyon[]: dizinin her elemanı şekle uymalı. Birinde alan eksik ya da fazlaysa az önceki hataları alırsın.map((s) => s.isim)vefilter((s) => s.hp > 0):s'ye tip yazmadık ve TS7006 da almadık. TypeScripttakim'ınSampiyon[]olduğunu bildiği için, geri çağırma fonksiyonunun (Ders 10) parametresininSampiyonolduğunu çıkarır.canlilar'a da tip yazmadık:filterdiziyi aynı tipte bıraktığı için o daSampiyon[].string[]yerineArray<string>yazıldığını da görürsün; ikisi aynı şey.
find (Ders 11) aradığını bulamazsa undefined döndürür ve TypeScript bunu bilir. takim.ts'nin sonuna, bir satır boşluk bırakıp ekle:
const lux = takim.find((s) => s.isim === "Lux")console.log(lux.hp)PS C:\kod\tipler> npx tsc --noEmittakim.ts:20:13 - error TS18048: 'lux' is possibly 'undefined'. 20 console.log(lux.hp) ~~~ Found 1 error in takim.ts:20lux'ın tipi Sampiyon | undefined: "ya bir şampiyon ya da hiçbir şey" (| işaretini birazdan ayrıntılı göreceksin). Takımda Lux yok; Node bu satırda TypeError: Cannot read properties of undefined (reading 'hp') ile dururdu. TS18048'in en sık geldiği yer burasıdır. Bulamama ihtimalini ele al:
const lux = takim.find((s) => s.isim === "Lux")if (lux) { console.log(lux.hp)} else { console.log("Lux takımda yok")}Artık tsc susar ve son çıktı satırı Lux takımda yok olur. if bloğunun içinde lux'ın undefined olamayacağını TypeScript biliyor; bunun adını birazdan koyacağız.
İç içe şekiller
Bir alanın tipi başka bir tip, hatta bir dizi olabilir; Ders 4'teki iç içe objeler gibi. envanter.ts:
type Esya = { ad: string fiyat: number} type Sampiyon = { isim: string esyalar: Esya[] konum: { x: number; y: number }} const garen: Sampiyon = { isim: "Garen", esyalar: [ { ad: "Uzun Kılıç", fiyat: 350 }, { ad: "Kalkan", fiyat: 450 }, ], konum: { x: 120, y: 80 },} const toplam = garen.esyalar.reduce((t, e) => t + e.fiyat, 0)console.log(garen.isim + " envanteri: " + toplam + " altın")console.log("Konum:", garen.konum.x, garen.konum.y)Garen envanteri: 800 altınKonum: 120 80esyalar: Esya[]:Esyaobjelerinden bir dizi. Tipler birbirinin içinde kullanılır;Esya'yı başka tiplerde de kullanabilirsin.konum: { x: number; y: number }: yalnız burada gereken küçük bir şekli ad vermeden, alanın içine yazdık. Tek satırda olduğu için alanlar;ile ayrıldı.reduce((t, e) => t + e.fiyat, 0)(Ders 11):t'nin tipi başlangıç değeri0'dan,e'ninki diziden çıkarıldı.- Bu dosyadaki
Sampiyon,sampiyon.ts'dekinden farklı bir tip. Her dosya kendi tiplerini tanımlar; bir dosyadaki tipi başka dosyada kullanmak da mümkün, ilerideki derslerde göreceksin.
Birleşim tipleri ve daraltma
koridor: string her metni kabul eder: "orta"'yı da, "Orta"'yı da, "mid"'i de, yazım hatalı "ortaa"'yı da. Bir alan yalnız belli değerleri alabiliyorsa onları tek tek sayarsın. koridor.ts:
type Koridor = "ust" | "orta" | "alt" | "orman" | "destek" type Sampiyon = { isim: string koridor: Koridor} const ahri: Sampiyon = { isim: "Ahri", koridor: "mid" }console.log(ahri){ isim: 'Ahri', koridor: 'mid' }PS C:\kod\tipler> npx tsc --noEmitkoridor.ts:8:40 - error TS2322: Type '"mid"' is not assignable to type 'Koridor'. 8 const ahri: Sampiyon = { isim: "Ahri", koridor: "mid" } ~~~~~~~ koridor.ts:5:5 - The expected type comes from property 'koridor' which is declared here on type 'Sampiyon' 5 koridor: Koridor ~~~~~~~ Found 1 error in koridor.ts:8| işaretini "ya da" diye oku: Koridor, "ust ya da orta ya da alt ya da orman ya da destek". Her seçenek tek bir değerden oluşan bir tip: "orta" tipi yalnız "orta" metnini kabul eder.
Mesaj yine TS2322; verilen tip tam o değer ('"mid"'), beklenen 'Koridor'. Ek satır beklentinin nereden geldiğini gösteriyor: Sampiyon'un koridor alanı. "mid"'i "orta" yap; tsc susar, çıktı { isim: 'Ahri', koridor: 'orta' } olur. VS Code'da koridor: " yazıp tırnağı açınca beş seçenek bir liste olarak çıkar: yazmana bile gerek kalmaz.
Daraltma: hangisi olduğunu sor
Bir değer birkaç tipten biri olabiliyorsa, onu kullanmadan önce hangisi olduğunu sorman gerekir. Bir oyuncu kimliği adresten metin olarak (" 42 "), veritabanından sayı olarak (7) gelebiliyor diyelim. id.ts:
function idCoz(id: string | number): number { return Number(id.trim())} console.log(idCoz(" 42 "))console.log(idCoz(7))42file:///C:/kod/tipler/id.ts:2 return Number(id.trim()) ^ TypeError: id.trim is not a function at idCoz (file:///C:/kod/tipler/id.ts:2:22) ... Node.js v24.20.0PS C:\kod\tipler> npx tsc --noEmitid.ts:2:22 - error TS2339: Property 'trim' does not exist on type 'string | number'. Property 'trim' does not exist on type 'number'. 2 return Number(id.trim()) ~~~~ Found 1 error in id.ts:2Metin için çalıştı, sayı gelince çöktü: sayıların trim metodu yok. tsc'nin mesajı iki satır: "string | number tipinde trim yok"; girintili alt satır da sebebini söylüyor: "çünkü number'da yok". Birleşimdeki her tip için geçerli olmayan bir şeyi kullanamazsın. Önce sor:
function idCoz(id: string | number): number { if (typeof id === "string") { return Number(id.trim()) } return id} console.log(idCoz(" 42 "))console.log(idCoz(7))427typeof id === "string" (Ders 23) çalışırken değerin türünü sorar. TypeScript bu soruyu okur ve if bloğunun içinde id'yi yalnız string sayar; orada trim serbest.
Blok return ile biter (erken çıkış); demek ki aşağı inildiyse değer metin değildir: son satırda id artık number. Bu işe daraltma denir. takim.ts'deki if (lux) de bir daraltmaydı: blokta lux artık undefined olamaz.
typeof sorusundan sonra TypeScript her yolda id'nin tipini biliyor.in ile daraltma
İki farklı şekilde obje gelebiliyorsa typeof işe yaramaz: ikisi için de "object" der. Bu kez hangi alanın olduğuna bakarsın. JavaScript'in in işareti "bu objede bu adda bir alan var mı?" diye sorar:
const teemo = { isim: "Teemo", hp: 80 }console.log("isim" in teemo)console.log("tur" in teemo)truefalseDers 5'teki for...in ile karıştırma: burada in bir döngü değil, bir soru. Bir hedef ya şampiyon ya da minyon olabiliyor. hedef.ts:
type Sampiyon = { isim: string hp: number} type Minyon = { tur: string hp: number} function hedefAdi(hedef: Sampiyon | Minyon): string { if ("isim" in hedef) { return hedef.isim } return hedef.tur + " minyonu"} console.log(hedefAdi({ isim: "Teemo", hp: 80 }))console.log(hedefAdi({ tur: "Kuşatma", hp: 300 }))TeemoKuşatma minyonu"isim" in hedef doğruysa TypeScript bloğun içinde hedef'i Sampiyon sayar, çünkü isim alanı yalnız onda var. Bloğun altında kalan tek seçenek Minyon.
Ayırt edici alan
En kullanışlı daraltma, bir alanın değerine bakmaktır. Bir maçta olan olayları tek bir dizide tutmak istiyorsun, ama her olay türünün alanları farklı. Her şekle, türünü söyleyen ortak bir tur alanı koy. olay.ts:
type Olay = | { tur: "oldurme"; oldUren: string; olen: string } | { tur: "ejderha"; takim: "mavi" | "kirmizi" } | { tur: "kule"; koridor: string } function olayYaz(olay: Olay): string { if (olay.tur === "oldurme") { return olay.oldUren + ", " + olay.olen + " adlı rakibi indirdi" } else if (olay.tur === "ejderha") { return olay.takim + " takım ejderhayı aldı" } else { return olay.koridor + " koridorunda kule yıkıldı" }} const mac: Olay[] = [ { tur: "oldurme", oldUren: "Jinx", olen: "Garen" }, { tur: "ejderha", takim: "mavi" }, { tur: "kule", koridor: "alt" },] for (const olay of mac) { console.log(olayYaz(olay))}Jinx, Garen adlı rakibi indirdimavi takım ejderhayı aldıalt koridorunda kule yıkıldıtype Olay = | {…} | {…} | {…}: üç şeklin birleşimi. Baştaki|yalnız hizalama içindir; okumayı kolaylaştırır.- Her şekilde
turvar ve her birinde değeri farklı bir sabit değer tipi.olay.tur === "oldurme"dediğin an TypeScript hangi şekilde olduğunu bilir: o bloktaoldUrenveolenkullanılabilir,takimkullanılamaz. - Son durumu
else if (olay.tur === "kule")değil, düzelseile yazdık: ilk iki koşul tutmadıysa geriyekulekalır ve TypeScript bunu bilir.else ifyazsaydın TS2366 alırdın ("üç koşul da tutmazsa ne döner?"); TypeScriptifzincirlerinde bütün seçenekleri saydığını kendiliğinden anlamaz.
Asıl kazanç, kodu sonradan değiştirirken gelir. Oyuna Baron olayını ekle (5. satır) ve dosyanın sonunda yalnız bir Baron olayı yazdır:
type Olay = | { tur: "oldurme"; oldUren: string; olen: string } | { tur: "ejderha"; takim: "mavi" | "kirmizi" } | { tur: "kule"; koridor: string } | { tur: "baron"; takim: "mavi" | "kirmizi" } function olayYaz(olay: Olay): string { if (olay.tur === "oldurme") { return olay.oldUren + ", " + olay.olen + " adlı rakibi indirdi" } else if (olay.tur === "ejderha") { return olay.takim + " takım ejderhayı aldı" } else { return olay.koridor + " koridorunda kule yıkıldı" }} console.log(olayYaz({ tur: "baron", takim: "kirmizi" }))undefined koridorunda kule yıkıldıPS C:\kod\tipler> npx tsc --noEmitolay.ts:13:21 - error TS2339: Property 'koridor' does not exist on type '{ tur: "kule"; koridor: string; } | { tur: "baron"; takim: "kirmizi" | "mavi"; }'. Property 'koridor' does not exist on type '{ tur: "baron"; takim: "kirmizi" | "mavi"; }'. 13 return olay.koridor + " koridorunda kule yıkıldı" ~~~~~~~ Found 1 error in olay.ts:13Node sessizce saçma bir cümle kurdu. tsc ise else dalına artık iki şeklin düşebileceğini fark etti, kule ve baron; ikincisinde koridor yok. Gerçek bir projede olayYaz gibi onlarca fonksiyon olur; yeni bir olay türü eklediğinde güncellemeyi unuttuğun her yeri tsc tek tek listeler. Baron için bir dal ekle:
} else if (olay.tur === "baron") { return olay.takim + " takım Baron'u kesti" } else { return olay.koridor + " koridorunda kule yıkıldı" }tsc susar, çıktı kirmizi takım Baron'u kesti olur.
any neden kötü, unknown neden iyi
Şimdiye kadar her değerin tipini ya sen söyledin ya TypeScript çıkardı. Bazı değerler ise programın dışından gelir: bir dosyadan, bir API'den, bir formdan. TypeScript onlar için iki özel tip sunar. veri.ts:
const metin = '{"isim": "Teemo", "hp": 80}'const veri = JSON.parse(metin) console.log(veri.isim)console.log(veri.hpp.toFixed(1))Teemofile:///C:/kod/tipler/veri.ts:5console.log(veri.hpp.toFixed(1)) ^ TypeError: Cannot read properties of undefined (reading 'toFixed') at file:///C:/kod/tipler/veri.ts:5:22 ... Node.js v24.20.0JSON metni çift tırnak içerdiği için dıştaki tırnaklar tek (Ders 13'teki gibi). 5. satırda hp yerine hpp yazılmış ve program çöktü. Asıl sorun şu: npx tsc --noEmit bu dosya için hiçbir şey yazmaz. Fareyi veri'nin üstüne getir: const veri: any.
any üç sebeple kötüdür:
- Denetimi kapatır.
veri.hpp.toFixedgibi bir yazım hatası bile geçer; tip denetiminin bütün faydası o değer için biter. - Bulaşır.
const hp = veri.hpyazarsanhpdeanyolur; onu döndüren fonksiyonun sonucu da. Tek biranykodun içinde yayılır. - Sessizdir. TS7006 gibi bir uyarı vermez; aramazsan
anyolduğunu fark etmezsin.
Kural basit: kendi kodunda any yazma. Bir değerin tipini bilmiyorsan unknown yaz. veri.ts'yi şöyle değiştir:
const metin = '{"isim": "Teemo", "hp": 80}'const veri: unknown = JSON.parse(metin) console.log(veri.isim)TeemoPS C:\kod\tipler> npx tsc --noEmitveri.ts:4:13 - error TS18046: 'veri' is of type 'unknown'. 4 console.log(veri.isim) ~~~~ Found 1 error in veri.ts:4Node için hiçbir şey değişmedi, yine Teemo yazdı. TypeScript ise artık temkinli: "veri bilinmeyen tipte". İçini kullanmadan önce ne olduğunu kanıtlamanı istiyor.
any denetimi kapatır, hata çalışırken patlar. unknown seni önce denetlemeye zorlar.Kanıt, daraltmanın ta kendisi. veri.ts'yi son kez değiştir; bu kez gelen veriyi denetleyip temiz bir Sampiyon'a çeviren bir fonksiyon yazıyorsun:
type Sampiyon = { isim: string hp: number} function sampiyonOku(veri: unknown): Sampiyon | null { if (typeof veri !== "object" || veri === null) { return null } if (!("isim" in veri) || typeof veri.isim !== "string") { return null } if (!("hp" in veri) || typeof veri.hp !== "number") { return null } return { isim: veri.isim, hp: veri.hp }} console.log(sampiyonOku(JSON.parse('{"isim": "Teemo", "hp": 80}')))console.log(sampiyonOku(JSON.parse('{"isim": "Teemo", "hpp": 80}')))console.log(sampiyonOku(JSON.parse('{"isim": "Teemo", "hp": "80"}')))console.log(sampiyonOku(JSON.parse("null"))){ isim: 'Teemo', hp: 80 }nullnullnulltypeof veri !== "object" || veri === null: önce, bu bir obje mi?null'a ayrıca bakıyoruz, çünkü JavaScript'in eski bir kusuru yüzündentypeof nullda"object"verir.!("isim" in veri) || typeof veri.isim !== "string":isimalanı var mı, varsa metin mi?indenetiminden sonra TypeScriptveri.isim'i okumana izin verir, ama tipi hâlâunknown'dır; metin olduğunutypeofile ayrıca kanıtlarız.- Üç denetimden geçen veriden yeni ve temiz bir
Sampiyonkurulur. Fazladan alanlar dışarıda kalır. - Dört deneme: doğru veri, yanlış ad (
hpp), metin olarak gelen sayı ("80", Ders 38'deki"2"gibi) venull. Yalnız ilki geçti.
Uzun görünüyor, öyle. Gerçek projelerde bu denetimleri zod gibi kütüphanelerle kısaltırsın (Ders 44). Fikir aynı kalır: dışarıdan gelen veri unknown'dır ve denetimden geçmeden içeri girmez.
Node'da .ts çalıştırmak ve tsc ile denetlemek
Dersin başından beri iki komut kullanıyorsun: node çalıştırıyor, tsc denetliyor. Neden Node ikisini birden yapmıyor? Çünkü Node TypeScript'i çalıştırırken tipleri okumaz bile: siler.
.ts dosyasını çalıştırırken tip notlarını aynı uzunlukta boşluklarla değiştirir. Noktalar silinen yerleri gösteriyor.Node .ts dosyasını açınca tip notlarını bulur ve her birinin yerine aynı uzunlukta boşluk koyar. Geriye düz JavaScript kalır ve o çalışır. Boşlukla değiştirmenin güzel bir yanı var: satır ve sütunlar kaymaz. Bu dersteki çalışma zamanı hatalarında oyuncu.ts:11:47 gibi yerlerin senin dosyandaki yerlerle birebir tuttuğunu gördün.
Bundan çıkan üç sonuç:
- Node tipleri denetlemez.
hp = "yetmiş"satırını gördün: Node çalıştırdı. Denetim tsc'nin işi. - Node
tsconfig.json'ı okumaz. O dosya yalnız tsc ve VS Code içindir. - Node silinemeyen sözdizimini çalıştırmaz. Silindiğinde yerine JavaScript kodu yazılması gereken birkaç TypeScript özelliği var; en bilineni
enum.
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only modeNe zaman çıkar? Başka dillerden ya da eski TypeScript kodlarından tanıdık gelen enum ile sabit bir liste tanımlayıp dosyayı node ile çalıştırınca. Dene, koridor-enum.ts:
enum Koridor { Ust, Orta, Alt,} console.log(Koridor.Orta)PS C:\kod\tipler> node koridor-enum.tsnode:internal/modules/run_main:107 triggerUncaughtException( ^ file:///C:/kod/tipler/koridor-enum.ts:1 > enum Koridor { Ust, Orta, Alt, > } SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode at parseTypeScript (node:internal/modules/typescript:68:40) ... at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:617:12) { code: 'ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX'} Node.js v24.20.0"TypeScript enum'u yalnız silme kipinde desteklenmiyor." enum bir tip notu değil: silinirse Koridor.Orta diye kullanılan değer de yok olur. TypeScript enum'u bir JavaScript objesine çevirerek çalıştırır; Node çeviri yapmadığı için programı hiç başlatmaz. İşin kötüsü, şu anki ayarlarınla npx tsc --noEmit bu dosyada hata bulmaz: TypeScript için enum geçerli bir sözdizimi.
Nasıl düzelir? Aynı işi birleşim tipi görür: type Koridor = "ust" | "orta" | "alt". tsc'nin de seni önceden uyarması için tsconfig.json'a bir satır ekle:
{ "compilerOptions": { "target": "esnext", "module": "nodenext", "types": ["node"], "strict": true, "erasableSyntaxOnly": true, "noEmit": true, "skipLibCheck": true }}PS C:\kod\tipler> npx tsc --noEmitkoridor-enum.ts:1:6 - error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled. 1 enum Koridor { ~~~~~~~ Found 1 error in koridor-enum.ts:1erasableSyntaxOnly: "yalnız silinebilen sözdizimine izin ver". Artık Node'un çalıştıramayacağı kodu tsc önceden söyler. Denemeden sonra koridor-enum.ts'yi sil. Node'un --experimental-transform-types seçeneği enum'u da çevirir, ama adından anlaşılacağı gibi deneyseldir; birleşim tipleri hem daha sade hem her yerde çalışır.
Günlük iş akışı
- Yazarken: VS Code açık dosyayı anında denetler. Kırmızı çizgiyi gördüğün an düzelt.
- Çalıştırmadan önce:
npx tsc --noEmitbütün projeyi denetler. Sessizse temiz. - Çalıştırırken:
node dosya.ts. - İstersen:
npx tsc --noEmit --watchile tsc'yi ikinci bir terminalde açık bırak; her kayıtta yeniden denetler. Ctrl+C ile durur.
VS Code kendi içinde bir TypeScript sürümü taşır: editördeki kırmızı çizgiler onun, terminaldeki denetim projendeki sürümün. Nadiren farklı sonuç verebilirler. İkisi çelişirse npx tsc --noEmit'e güven; ekip arkadaşların ve sunucular da onu çalıştırır.
Tip hata mesajlarını okumak
Bu derste on kadar farklı tip hatası gördün. Hepsi aynı kalıpla yazılır; kalıbı bir kez çözersen yenilerini de okursun.
Mesajların gövdesi birkaç kalıptan birine uyar. İçinde iki tip geçiyorsa sıraları hep aynıdır: önce senin verdiğin, sonra oranın beklediği.
- Type A is not assignable to type B: A senin verdiğin, B oranın beklediği tip (TS2322).
- Argument of type A is not assignable to parameter of type B: aynısı, bu kez fonksiyon çağrısında (TS2345).
- Property x does not exist on type T:
Ttipindexdiye bir alan yok (TS2339; benzer bir ad varsa öneriyle birlikte TS2551). - Parameter x implicitly has an 'any' type:
x'e tip yazılmamış (TS7006). - 'x' is possibly 'undefined': önce denetle (TS18048;
nulliçin TS18047).
Zincirleme mesajlar
Tipler iç içe olunca mesaj birkaç satıra yayılır. Bir formdan gelen şampiyonu takıma eklemeye çalış, form.ts:
type Sampiyon = { isim: string hp: number koridor: string} const takim: Sampiyon[] = [] const formdanGelen = { isim: "Lux", hp: "90", koridor: "orta" }takim.push(formdanGelen)console.log(takim)PS C:\kod\tipler> npx tsc --noEmitform.ts:10:12 - error TS2345: Argument of type '{ isim: string; hp: string; koridor: string; }' is not assignable to parameter of type 'Sampiyon'. Types of property 'hp' are incompatible. Type 'string' is not assignable to type 'number'. 10 takim.push(formdanGelen) ~~~~~~~~~~~~ Found 1 error in form.ts:10İlk satır genel resmi verir: "bu obje Sampiyon parametresine verilemez". Her girintili satır bir adım daha yaklaşır: "hp alanlarının tipleri uyuşmuyor", sonra "metin, sayıya atanamaz". En içteki satır asıl sebeptir. Uzun bir mesajda kaybolursan en alttaki girintili satırdan başla.
Burada çare, formdan gelen değeri sayıya çevirmek: 10. satırı takim.push({ ...formdanGelen, hp: Number(formdanGelen.hp) }) yap (Ders 12'deki yayma). tsc susar, çıktı [ { isim: 'Lux', hp: 90, koridor: 'orta' } ] olur.
Ek satırlar ve özet tablosu
Boşlukla girintili gelen ek bilgiler ('gold' is declared here., The expected type comes from property 'koridor'…) hatanın değil, beklentinin nerede tanımlandığını gösterir: "bu alan zorunlu, çünkü şurada böyle yazıyor". Bazen asıl düzeltilecek yer orasıdır: belki değer değil, tip yanlıştır.
Birden çok dosyada hata varsa tsc mesajların sonuna küçük bir tablo ekler. hasar.ts'de tipsiz parametreler ve oyuncu.ts'de denetlenmemiş takım adı aynı anda dursaydı:
PS C:\kod\tipler> npx tsc --noEmit...Found 3 errors in 2 files. Errors Files 2 hasar.ts:5 1 oyuncu.ts:11Node bir çalıştırmada yalnız ilk hatayı söylüyordu; tsc hepsini birden listeler. Yine de en üsttekinden başla: bir hata çoğu zaman altındakilere de yol açar.
| Kod | Ne diyor | İlk bakılacak yer |
|---|---|---|
| TS2322 | Bu değer bu tipe konamaz | Değer mi yanlış, tip mi? |
| TS2345 | Bu argüman bu parametreye verilemez | Değeri kaynağında çevir |
| TS2339, TS2551 | Bu tipte böyle bir alan yok | Yazım; alan tipte var mı? |
| TS2741 | Zorunlu alan eksik | Objeyi tamamla ya da alanı ? yap |
| TS2353 | Tipte olmayan fazla alan | Yazım hatası mı? |
| TS2554 | Argüman sayısı yanlış | Fonksiyonun tanımına bak |
| TS2366 | Her yolda return yok | Sınır değerlerini düşün |
| TS7006 | Parametrenin tipi yok | Tipi yaz |
| TS18046 | unknown değer denetlenmeden kullanılmış | Önce daralt |
| TS18048, TS18047 | undefined ya da null olabilir | if, ?., ?? |
Sık hatalar
Tip hatalarının kartlarını bölümlerin içinde gördün. Bunlar araçla ilgili olanlar.
The term 'tsc' is not recognizedNe zaman çıkar? npx'i unutup yalnız tsc yazınca. TypeScript'i bilgisayarın geneline değil, projeye kurdun; tsc komutu yalnız projenin node_modules klasöründe var.
PS C:\kod\tipler> tsc --noEmittsc : The term 'tsc' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.At line:1 char:1+ tsc --noEmit+ ~~~ + CategoryInfo : ObjectNotFound: (tsc:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundExceptionDers 0'daki node hatasının aynısı. Windows'unun dili Türkçe olsa da PowerShell bu mesajı çoğu zaman İngilizce yazar; Türkçe gelirse 'tsc' terimi … tanınmıyor diye başlar, anlamı aynıdır.
Nasıl düzelir? Başına npx ekle: npx tsc --noEmit. İnternette önerilen npm install -g typescript (bilgisayarın geneline kurmak) da işe yarar, ama her projeye kendi sürümünü kurmak daha güvenli: genel kurulum zamanla projendeki sürümden ayrılır.
This is not the tsc command you are looking forNe zaman çıkar? npx tsc'yi TypeScript kurulu olmayan bir klasörde çalıştırınca: yanlış klasördeysen ya da npm install -D typescript'i atladıysan. npx komutu projede bulamayınca npm'de tsc adlı paketi arar ve önce sorar:
PS C:\kod> npx tsc --noEmitNeed to install the following packages:tsc@2.0.4Ok to proceed? (y)tsc@2.0.4 TypeScript değil, yıllar önce bırakılmış aynı adlı bir paket. Varsayılan cevap evet olduğu için Enter'a basarsan iner ve yalnız şunu yazar (öncesinde npm'in kurulum satırları da görünebilir):
This is not the tsc command you are looking for To get access to the TypeScript compiler, tsc, from the command line either: - Use npm install typescript to first add TypeScript to your project before using npx- Use yarn to avoid accidentally running code from un-installed packages"Aradığın tsc komutu bu değil; önce TypeScript'i projene kur."
Nasıl düzelir? Soruya n yazıp Enter'a bas. İstemdeki klasörün proje klasörün (C:\kod\tipler) olduğunu denetle; doğruysa npm install -D typescript ile TypeScript'i kur.
npx tsc --noEmit hata yerine uzun bir yardım metni yazıyorNe zaman çıkar? Klasörde tsconfig.json yoksa: dosyayı oluşturmayı unuttuysan, başka bir klasöre kaydettiysen ya da adını yanlış verdiysen (tsconfig.js, tsconfig.json.txt). tsc denetleyecek bir proje bulamayınca kullanım kılavuzunu yazar:
PS C:\kod\tipler> npx tsc --noEmitVersion 7.0.2tsc: The TypeScript Compiler - Version 7.0.2 COMMON COMMANDS tsc Compiles the current project (tsconfig.json in the working directory.)...İlk komutun açıklaması ipucunu veriyor: tsc tek başına, çalışılan klasördeki tsconfig.json'ın tarif ettiği projeyi derler.
Nasıl düzelir? VS Code'un dosya listesinde tsconfig.json'ın package.json ile aynı yerde ve tam bu adla durduğunu denetle; Ders 0'daki gizli uzantı tuzağını hatırla.
error TS5112: tsconfig.json is present but will not be loaded if files are specified on commandline.Ne zaman çıkar? Yalnız tek bir dosyayı denetlemek için adını komuta yazınca: npx tsc --noEmit hasar.ts.
PS C:\kod\tipler> npx tsc --noEmit hasar.tserror TS5112: tsconfig.json is present but will not be loaded if files are specified on commandline. Use '--ignoreConfig' to skip this error."Komutta dosya adı verdin; tsconfig.json okunmayacak." Dosya adı verilince tsc ayar dosyasını bırakıp varsayılan ayarlarla çalışır; types gibi ayarların sessizce kaybolmasın diye seni durduruyor.
Nasıl düzelir? Dosya adı yazma: npx tsc --noEmit bütün projeyi zaten denetler ve her hatanın hangi dosyada olduğunu yazar.
error TS2591: Cannot find name 'process'.Ne zaman çıkar? process.argv (Ders 38) ya da process.env (Ders 29) kullanan bir dosyayı, tsconfig.json'da "types": ["node"] olmadan denetleyince. TypeScript 6'dan beri tip paketleri kendiliğinden yüklenmiyor; @types/node kurulu olsa bile listede adı yoksa okunmaz. Dene: tsconfig.json'dan "types": ["node"], satırını geçici olarak sil ve şu dosyayı yaz:
const oyuncu = process.argv[2] ?? "misafir"console.log("Merhaba " + oyuncu)PS C:\kod\tipler> npx tsc --noEmitselam.ts:1:16 - error TS2591: Cannot find name 'process'. Do you need to install type definitions for node? Try `npm i --save-dev @types/node` and then add 'node' to the types field in your tsconfig. 1 const oyuncu = process.argv[2] ?? "misafir" ~~~~~~~ Found 1 error in selam.ts:1Node için sorun yok: node selam.ts tipleri okumadığı için Merhaba misafir yazar. Eksik olan yalnız TypeScript'in process'i tanıması.
Nasıl düzelir? Mesaj iki adımı da söylüyor: @types/node'u kur (npm i --save-dev, bildiğin npm install -D ile aynı komut: i, install'ın kısaltması; --save-dev, -D'nin uzun yazılışı) ve tsconfig.json'daki types alanına "node" ekle. Sen ilkini dersin başında yaptın; sildiğin satırı geri koyman yeter.
Görevler
Görevleri C:\kod\tipler klasöründe, her birini kendi dosyasında yap. Her görevde iki denetim var: npx tsc --noEmit sessiz kalmalı, node dosya.ts beklenen çıktıyı vermeli. Önce kendin dene, takılırsan ipuçlarını sırayla aç.
Birim satışı
TFT'de bir birimi satınca altın geri alırsın. Bu görevin kuralı: 1 yıldızlı birim 1 kopya, 2 yıldızlı 3 kopya, 3 yıldızlı 9 kopya sayılır; satış değeri maliyet çarpı kopya sayısıdır. Geçersiz bir yıldız (0, 4…) için kopya sayısı 0.
birim.ts'de iki fonksiyon yaz: kopyaSayisi(yildiz) ve satisDegeri(maliyet, yildiz). Parametrelerin ve dönüş değerlerinin tipini yaz; değişkenlerin tipini TypeScript çıkarsın. Maliyeti 4 olan Annie'yi 1, 2, 3, 0 ve 4 yıldızla dene:
Annie 4Annie 12Annie 36Annie 0Annie 0Bitirince bilerek console.log(satisDegeri(4, "3")) satırını ekle. Önce node ile çalıştır, sonra tsc'nin ne dediğini oku.
İpucu 1
Kalıp: function kopyaSayisi(yildiz: number): number { … }. Üç yıldız durumunu if / else if ile ayır, en sonda return 0.
İpucu 2
satisDegeri tek satır: return maliyet * kopyaSayisi(yildiz). const birim = "Annie" ve const maliyet = 4 için tip notu gerekmez.
Çözümü göster
function kopyaSayisi(yildiz: number): number { if (yildiz === 1) { return 1 } else if (yildiz === 2) { return 3 } else if (yildiz === 3) { return 9 } return 0} function satisDegeri(maliyet: number, yildiz: number): number { return maliyet * kopyaSayisi(yildiz)} const birim = "Annie"const maliyet = 4 console.log(birim, satisDegeri(maliyet, 1))console.log(birim, satisDegeri(maliyet, 2))console.log(birim, satisDegeri(maliyet, 3))console.log(birim, satisDegeri(maliyet, 0))console.log(birim, satisDegeri(maliyet, 4))Annie 4Annie 12Annie 36Annie 0Annie 0Son iki satır sınır denemesi: geçersiz yıldızlar 0 veriyor. Denemedeki satisDegeri(4, "3") satırını 24. satıra yazdıysan Node 0 yazar: "3" === 3 yanlış olduğu için kopya sayısı 0 çıktı. Hata yok, ama sonuç yanlış. tsc ise yakalar:
PS C:\kod\tipler> npx tsc --noEmitbirim.ts:24:28 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. 24 console.log(satisDegeri(4, "3")) ~~~ Found 1 error in birim.ts:24Büyü bekleme süresi: hata avı
Arkadaşının yazdığı buyu.ts'de üç tip hatası var. Program çalışıyor ama iki satırda da false yazıyor. Doğrusu: Sıçrama için false (120 saniye geçmiş, 300 gerekiyor), Tutuşturma için true (200 saniye geçmiş, 180 yetiyor). Kodu gözle aramadan, yalnız tsc'nin mesajlarını okuyarak düzelt.
type Buyu = { ad: string bekleme: number} const sicrama: Buyu = { ad: "Sıçrama", bekleme: "300" }const tutusturma: Buyu = { ad: "Tutuşturma", bekleme: 180 } function hazirMi(buyu: Buyu, gecenSure) { return gecenSure >= buyu.sure} console.log(hazirMi(sicrama, 120))console.log(hazirMi(tutusturma, 200))falsefalsePS C:\kod\tipler> npx tsc --noEmitbuyu.ts:6:40 - error TS2322: Type 'string' is not assignable to type 'number'. 6 const sicrama: Buyu = { ad: "Sıçrama", bekleme: "300" } ~~~~~~~ buyu.ts:3:5 - The expected type comes from property 'bekleme' which is declared here on type 'Buyu' 3 bekleme: number ~~~~~~~ buyu.ts:9:30 - error TS7006: Parameter 'gecenSure' implicitly has an 'any' type. 9 function hazirMi(buyu: Buyu, gecenSure) { ~~~~~~~~~ buyu.ts:10:30 - error TS2339: Property 'sure' does not exist on type 'Buyu'. 10 return gecenSure >= buyu.sure ~~~~ Found 3 errors in the same file, starting at: buyu.ts:6Hepsini düzeltince sona bir sınır denemesi ekle: hazirMi(tutusturma, 180). Beklenen çıktı:
falsetruetrueİpucu 1
İlk mesaj 6. satırda: bekleme alanına ne tür bir değer verilmiş, tip ne bekliyor? Ek satır beklentinin tipin 3. satırından geldiğini gösteriyor.
İpucu 2
TS7006: gecenSure'ün tipi yok. Kaç saniye geçtiğini tutan bir parametrenin tipi ne olmalı? Fonksiyonun dönüş tipini de yaz: >= hep true ya da false verir.
İpucu 3
TS2339: Buyu tipinde sure diye bir alan yok. Tipte bekleme süresinin adı ne?
Çözümü göster
type Buyu = { ad: string bekleme: number} const sicrama: Buyu = { ad: "Sıçrama", bekleme: 300 }const tutusturma: Buyu = { ad: "Tutuşturma", bekleme: 180 } function hazirMi(buyu: Buyu, gecenSure: number): boolean { return gecenSure >= buyu.bekleme} console.log(hazirMi(sicrama, 120))console.log(hazirMi(tutusturma, 200))console.log(hazirMi(tutusturma, 180))falsetruetrueSon satır sınır değeri: tam 180 saniyede büyü hazır, çünkü >= kullandık. > yazsaydın false çıkardı ve tsc bunu yakalayamazdı; bu bir mantık hatası, tip hatası değil.
Maç özeti
mac.ts'de bir maç kaydının şeklini bu kez interface ile tanımla: sampiyon (metin), kill, olum, asist (sayı) ve isteğe bağlı dakika (sayı; bazı kayıtlarda maç süresi yok). İki fonksiyon yaz:
kda(mac): ölüm 0 ise"Kusursuz", değilse(kill + asist) / olumiki basamakla (Ders 9).killHizi(mac): dakika başına kill, iki basamakla ve sonunakill/dkeklenmiş. Süre yoksa ya da0ise"süre bilinmiyor".
Maçlar: Jinx 7/2/9, 28 dakika; Lux 10/0/6, süre yok; Garen 3/5/1, süre 0 (bozuk kayıt). Üç maçlık bir diziyi gez ve her maç için bir satır yazdır:
Jinx: KDA 8.00, 0.25 kill/dkLux: KDA Kusursuz, süre bilinmiyorGaren: KDA 0.80, süre bilinmiyorİpucu 1
interface MacKaydi { … } içinde isteğe bağlı alan dakika?: number. Dizi: const maclar: MacKaydi[] = [ … ].
İpucu 2
mac.dakika'nın tipi number | undefined; doğrudan bölersen TS18048 alırsın. if (!mac.dakika) hem undefined'ı hem 0'ı yakalar (Ders 12'deki yanlış sayılan değerler).
İpucu 3
Satırı şablon metinle kur: `${mac.sampiyon}: KDA ${kda(mac)}, ${killHizi(mac)}`.
Çözümü göster
interface MacKaydi { sampiyon: string kill: number olum: number asist: number dakika?: number} function kda(mac: MacKaydi): string { if (mac.olum === 0) { return "Kusursuz" } return ((mac.kill + mac.asist) / mac.olum).toFixed(2)} function killHizi(mac: MacKaydi): string { if (!mac.dakika) { return "süre bilinmiyor" } return (mac.kill / mac.dakika).toFixed(2) + " kill/dk"} const maclar: MacKaydi[] = [ { sampiyon: "Jinx", kill: 7, olum: 2, asist: 9, dakika: 28 }, { sampiyon: "Lux", kill: 10, olum: 0, asist: 6 }, { sampiyon: "Garen", kill: 3, olum: 5, asist: 1, dakika: 0 },] for (const mac of maclar) { console.log(`${mac.sampiyon}: KDA ${kda(mac)}, ${killHizi(mac)}`)}Jinx: KDA 8.00, 0.25 kill/dkLux: KDA Kusursuz, süre bilinmiyorGaren: KDA 0.80, süre bilinmiyorİki sınır değeri var. Lux'un ölümü 0: kda bölmeden önce bakıyor. Garen'in süresi 0: mac.dakika !== undefined diye denetleseydin 0 denetimden geçerdi, 3 / 0 da Infinity verirdi. tsc ikisini de umursamaz, çünkü ikisi de tip olarak doğru; sınırları denemek hâlâ senin işin.
TFT ganimeti
TFT'de ganimet kürelerinden üç tür ödül çıkıyor: altın (miktarıyla), birim (adı ve 1–3 yıldızıyla) ya da eşya (adıyla). odul.ts'de:
Odultipini ayırt edici alanlı bir birleşim olarak yaz. Alanın adıtur, değerleri"altin","birim","esya". Yıldız yalnız1 | 2 | 3olabilsin.odulYaz(odul)her ödülü bir metne çevirsin.toplamAltin(oduller)bir ödül dizisindeki altınları toplasın; boş dizi ve altınsız dizi için0döndürsün.
Dört ödüllük bir ganimetle (3 altın, 2 yıldızlı Annie, Uzun Kılıç, 5 altın) ve iki sınır denemesiyle beklenen çıktı:
3 altın2 yıldızlı Annieeşya: Uzun Kılıç5 altınToplam altın: 8Boş ganimet: 0Altınsız: 0Bitirince dosyanın sonuna bilerek iki hatalı ödül yaz: { tur: "altın", miktar: 5 } (Türkçe ı ile) ve 4 yıldızlı bir birim. Mesajları oku.
İpucu 1
Şekil: type Odul = | { tur: "altin"; miktar: number } | { … } | { … }. Yıldız alanı: yildiz: 1 | 2 | 3.
İpucu 2
odulYaz'da if (odul.tur === "altin"), else if (odul.tur === "birim"), son durum için düz else. Her bloğun içinde yalnız o şeklin alanları kullanılabilir.
İpucu 3
toplamAltin'de let toplam = 0 ve for...of. Döngünün içinde if (odul.tur === "altin") ile daralt, sonra odul.miktar'ı ekle.
Çözümü göster
type Odul = | { tur: "altin"; miktar: number } | { tur: "birim"; ad: string; yildiz: 1 | 2 | 3 } | { tur: "esya"; ad: string } function odulYaz(odul: Odul): string { if (odul.tur === "altin") { return `${odul.miktar} altın` } else if (odul.tur === "birim") { return `${odul.yildiz} yıldızlı ${odul.ad}` } else { return `eşya: ${odul.ad}` }} function toplamAltin(oduller: Odul[]): number { let toplam = 0 for (const odul of oduller) { if (odul.tur === "altin") { toplam = toplam + odul.miktar } } return toplam} const ganimet: Odul[] = [ { tur: "altin", miktar: 3 }, { tur: "birim", ad: "Annie", yildiz: 2 }, { tur: "esya", ad: "Uzun Kılıç" }, { tur: "altin", miktar: 5 },] for (const odul of ganimet) { console.log(odulYaz(odul))}console.log("Toplam altın:", toplamAltin(ganimet))console.log("Boş ganimet:", toplamAltin([]))console.log("Altınsız:", toplamAltin([{ tur: "esya", ad: "Kalkan" }]))3 altın2 yıldızlı Annieeşya: Uzun Kılıç5 altınToplam altın: 8Boş ganimet: 0Altınsız: 0Hatalı iki ödülü bir satır boşluk bırakıp const bozuk1: Odul = … ve const bozuk2: Odul = … diye eklediysen:
PS C:\kod\tipler> npx tsc --noEmitodul.ts:40:24 - error TS2820: Type '"altın"' is not assignable to type '"altin" | "birim" | "esya"'. Did you mean '"altin"'? 40 const bozuk1: Odul = { tur: "altın", miktar: 5 } ~~~ odul.ts:2:9 - The expected type comes from property 'tur' which is declared here on type 'Odul' 2 | { tur: "altin"; miktar: number } ~~~ odul.ts:41:51 - error TS2322: Type '4' is not assignable to type '1 | 2 | 3'. 41 const bozuk2: Odul = { tur: "birim", ad: "Annie", yildiz: 4 } ~~~~~~ Found 2 errors in the same file, starting at: odul.ts:40İlki TS2322'nin öneri getiren biçimi (TS2820): ı ile i'yi ayırt etti. İkincisinde verilen tip 4, beklenen 1 | 2 | 3. Node ikisini de sorgusuz kabul ederdi.
Skor tablosu dosyası
Bir oyun sunucusu skor tablosunu JSON metni olarak gönderiyor, ama veri her zaman temiz değil. skor.ts'de skorlariOku(metin: string) fonksiyonunu yaz; Skor objelerinden (oyuncu metin, puan sayı) bir dizi döndürsün:
- Metin geçerli bir JSON değilse boş dizi.
- JSON bir dizi değilse boş dizi.
- Dizinin her elemanı için: obje değilse,
oyuncumetin değilse ya dapuansayı değilse o elemanı atla. Fazla alanlar sonuca girmesin. anyyazmak yok:JSON.parse'ın sonucunuunknownbir değişkene koy.
Şu dört denemeyle dene:
const kayit = '[{"oyuncu": "Deniz", "puan": 1200}, {"oyuncu": "Arda", "puan": "900"}, null, {"oyuncu": "Ece", "puan": 0, "rozet": "altın"}, 42]' console.log(skorlariOku(kayit))console.log(skorlariOku("[]"))console.log(skorlariOku('{"oyuncu": "Deniz", "puan": 1200}'))console.log(skorlariOku("bozuk"))Beklenen çıktı:
[ { oyuncu: 'Deniz', puan: 1200 }, { oyuncu: 'Ece', puan: 0 } ][][][]İpucu 1
İşi ikiye böl: tek bir elemanı denetleyen skorOku(oge: unknown): Skor | null (bölümdeki sampiyonOku gibi) ve bütün metni okuyan skorlariOku.
İpucu 2
İpucu 3
Array.isArray sorusundan sonra TypeScript diziyi any[] sayar; elemanları da any olur. Her elemanı unknown parametre alan skorOku'ya verdiğin için denetimler yine işler. Sonuç null değilse yeni diziye push et.
Çözümü göster
type Skor = { oyuncu: string puan: number} function skorOku(oge: unknown): Skor | null { if (typeof oge !== "object" || oge === null) { return null } if (!("oyuncu" in oge) || typeof oge.oyuncu !== "string") { return null } if (!("puan" in oge) || typeof oge.puan !== "number") { return null } return { oyuncu: oge.oyuncu, puan: oge.puan }} function skorlariOku(metin: string): Skor[] { let veri: unknown try { veri = JSON.parse(metin) } catch (hata) { return [] } if (!Array.isArray(veri)) { return [] } const skorlar: Skor[] = [] for (const oge of veri) { const skor = skorOku(oge) if (skor !== null) { skorlar.push(skor) } } return skorlar} const kayit = '[{"oyuncu": "Deniz", "puan": 1200}, {"oyuncu": "Arda", "puan": "900"}, null, {"oyuncu": "Ece", "puan": 0, "rozet": "altın"}, 42]' console.log(skorlariOku(kayit))console.log(skorlariOku("[]"))console.log(skorlariOku('{"oyuncu": "Deniz", "puan": 1200}'))console.log(skorlariOku("bozuk"))[ { oyuncu: 'Deniz', puan: 1200 }, { oyuncu: 'Ece', puan: 0 } ][][][]Sınır değerleri: Arda'nın puanı metin olduğu için atlandı; null ve 42 obje olmadığı için atlandı. Ece'nin puanı 0 ve kaldı: if (!oge.puan) gibi bir denetim onu yanlışlıkla atardı, typeof oge.puan !== "number" atmaz. rozet sonuca girmedi, çünkü yeni objeyi kendimiz kurduk. "[]" boş bir dizi, {…} dizi değil, "bozuk" JSON değil: üçü de boş dizi döndürdü.
Kendini sına
Soru 1
Bu satırlarda TypeScript her değişkene hangi tipi verir?
let altin = 300const koridor = "orta"let canli = trueconst takim = ["Ahri", "Lux"]Cevabı göster
altin: number. koridor: "orta"; const asla değişmeyeceği için tipi tam o değer. canli: boolean. takim: string[]. Hiçbirine tip notu gerekmiyor; VS Code'da fareyi adların üstüne getirerek kendin görebilirsin.
Soru 2
Bu dosyayı node ile çalıştırırsan ne olur? npx tsc --noEmit ne der?
function kalanMana(mana: number, bedel: number): number { return mana - bedel} console.log(kalanMana(100, "30"))Cevabı göster
Node 70 yazar: tipleri silip çalıştırır ve - işareti "30"'u sayıya çevirir. tsc ise TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. der. Sonuç bu kez doğru çıktı, ama söz bozuldu: aynı değer + ile kullanılsaydı "10030" gibi bir şey çıkardı. Tip denetimi şans eseri doğru çıkan sonuçları da yakalar.
Soru 3
Mesajı oku: hata hangi dosyada, hangi satır ve sütunda? Verilen tip ne, beklenen tip ne?
kritik.ts:9:7 - error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. 9 duyur(90) ~~Cevabı göster
kritik.ts'nin 9. satırı, 7. sütunu: 90'ın başladığı yer. Verilen tip number (90), beklenen tip string (duyur'un mesaj parametresi). Ya sayıyı metne çevirip ver (duyur("90") ya da duyur(String(90))) ya da fonksiyonun gerçekten sayı alması gerekiyorsa parametrenin tipini değiştir.
Soru 4
any ile unknown'ın farkı ne? İkisi de "her şey olabilir" demiyor mu?
Cevabı göster
İkisi de her değeri kabul eder; fark, sonrasında ne yapmana izin verdikleri. any denetimi kapatır: alanını okursun, metodunu çağırırsın, onu her yere verirsin ve hiçbir hata almazsın. unknown hiçbir şeye izin vermez: önce typeof, in gibi denetimlerle ne olduğunu kanıtlaman gerekir. Dışarıdan gelen veride unknown kullan; any hatayı yalnız çalışma zamanına erteler.
Soru 5
if bloğunun içinde ve fonksiyonun son satırında hedef'in tipi nedir?
type Sampiyon = { isim: string; hp: number }type Minyon = { tur: string; hp: number } function hedefAdi(hedef: Sampiyon | Minyon): string { if ("isim" in hedef) { return hedef.isim } return hedef.tur + " minyonu"}Cevabı göster
Blokta Sampiyon: isim alanı yalnız onda var, in sorusu tipi daralttı. Son satırda Minyon: blok return ile bittiği için aşağı inildiyse isim yok demektir. Son satırda hedef.isim yazsaydın TS2339 alırdın.
Soru 6
npx tsc --noEmit hiçbir hata göstermiyor ama node oyun.ts çalıştırınca ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX alıyorsun. Ne olabilir, tsc'nin bunu önceden söylemesi için ne yaparsın?
Cevabı göster
Dosyada Node'un silemediği bir TypeScript sözdizimi var, büyük olasılıkla bir enum. TypeScript için geçerli olduğundan tsc susar, ama Node tipleri yalnız silerek çalıştırdığı için enum'u çalıştıramaz. tsconfig.json'a "erasableSyntaxOnly": true eklersen tsc aynı satırda TS1294 verir. enum'un yerine birleşim tipi yaz: type Koridor = "ust" | "orta" | "alt".
Soru 7
type Oyuncu = { ad: string; takim?: string } için oyuncu.takim'ın tipi nedir? oyuncu.takim.length neden hata verir? İki düzeltme yolu yaz.
Cevabı göster
Tipi string | undefined: ? alanı isteğe bağlı yapar. .length bir metin özelliği, undefined'da yok; tsc TS18048: 'oyuncu.takim' is possibly 'undefined'. der, Node da takımsız bir oyuncuda TypeError verir. Düzeltmeler: oyuncu.takim?.length ?? 0 ya da if (oyuncu.takim) { … } ile önce denetlemek.
Kayıt noktası
Commit'ten önce son bir denetim yap: npx tsc --noEmit sessiz kalmalı. Bilerek hatalı bıraktığın bir satır kaldıysa (örneğin form.ts'nin 10. satırı ya da takimsiz.ts'nin son satırı) bölümdeki düzeltmeyi uygula; görevlerde denemek için eklediğin satırları (birim.ts'deki satisDegeri(4, "3"), odul.ts'deki iki bozuk ödül) sil. Sonra klasörde .gitignore adlı bir dosya oluştur ve içine node_modules/ yaz (Ders 14); kurulu paketler Git'e girmez.
Sıradaki derste arayüze geçiyorsun: Vite ile bir React projesi açacak, JSX yazacak ve sayfayı küçük, yeniden kullanılabilir bileşenlere böleceksin.