İçeriğe geç
XDD.baby Yazılım Öğrenme
Sözlük Hata rehberi 0/56

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
  • type ve interface ile 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ıp typeof, in ve ayırt edici alanla daraltabilirsin
  • Dışarıdan gelen veriyi any yerine unknown olarak alıp denetleyerek tipli bir objeye çevirebilirsin
  • .ts dosyasını node ile çalıştırıp npx tsc --noEmit ile denetleyebilir, tsconfig.json'ın temel ayarlarını açıklayabilirsin
  • TS2322, TS2345, TS2339, TS7006 ve TS18048 mesajlarında yeri, verilen ve beklenen tipi bulup hatayı düzeltebilirsin
Bu sayfada
  1. Neden tip: hatayı çalıştırmadan görmek
  2. TypeScript'i projeye kurmak
  3. Temel tipler
  4. Fonksiyonlara tip vermek
  5. type ve interface: objenin şekli
  6. Dizi ve obje tipleri
  7. Birleşim tipleri ve daraltma
  8. any neden kötü, unknown neden iyi
  9. Node'da .ts çalıştırmak ve tsc ile denetlemek
  10. Tip hata mesajlarını okumak
  11. Sık hatalar
  12. Görevler
  13. Kendini sına
  14. 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:

seri.js
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)    }}
Hata çıktısı
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.0

Program 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:

seri.ts — tipler — Visual Studio Code
seri.ts
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)    }}
PROBLEMSOUTPUTDEBUG CONSOLETERMINAL
seri.ts  1  Property 'toUppercase' does not exist on type 'string'.    Did you mean 'toUpperCase'? ts(2551) [Ln 6, Col 31]
Ln 1, Col 1Spaces: 4UTF-8TypeScript

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.

JavaScript: hata çalışırken patlar Yazdın Çalıştırdın Seri 1–4 sorun yok gibi Seri 5 TypeError fark ettiğin an TypeScript: hata yazarken görünür Yazdın Kırmızı çizgi TS2551 Düzelttin Çalıştırdın 5 tur da doğru fark ettiğin an zaman
Şekil 39.1 Aynı hata, iki farklı an. JavaScript'te hatayı ancak o satır çalışınca görürsün; TypeScript'te yazdığın anda.

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:

Terminal — PowerShell
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.2
  • npm pkg set type=module: Ders 14'teki "type": "module" ayarı. .ts dosyaların da ES modülü sayılır.
  • -D: paketleri package.json'da dependencies yerine devDependencies altına yazar. Uzun yazılışı --save-dev.
  • typescript: TypeScript'in kendisi. İçinden tsc komutu çıkar.
  • @types/node@24: Node 24'ün tip tanımları. process, Buffer gibi Node'a özgü adların tiplerini TypeScript buradan öğrenir. @24 yazmazsan daha yeni bir Node sürümünün tanımları gelir.
  • npx tsc --version: npx önce projenin node_modules klasörüne bakar; komut oradaysa onu çalıştırır. Ders 18'deki npx 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:

tsconfig.json
{    "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. Yazmazsan process gibi adları tanımaz.
  • "strict": true: en sıkı denetim. Bu derste göreceğin "tipi belirsiz parametre" ve "undefined olabilir" 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". tsc istersen her .ts'nin yanına bir .js yazabilir; bize gerekmiyor, çünkü Node .ts'yi doğrudan çalıştırıyor. Komutta da --noEmit yazacağız; ayar dosyasında olduğu için şart değil, ama komutu okuyan herkes ne yaptığını hemen anlasın.
  • "skipLibCheck": true: node_modules içindeki hazır tip dosyalarını yeniden denetleme; zaman kazandırır.

Şimdi bütün projeyi denetle:

Terminal — PowerShell
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:6

VS 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:

seri.ts — tipler — Visual Studio Code
seri.ts
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)    }}
PROBLEMSOUTPUTDEBUG CONSOLETERMINAL
PS C:\kod\tipler> npx tsc --noEmitPS C:\kod\tipler> node seri.tsJinx seri: 1Jinx seri: 2Jinx seri: 3Jinx seri: 4JINX: PENTAKILL!
Ln 1, Col 1Spaces: 4UTF-8TypeScript

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:

temel.ts
let isim: string = "Ahri"let hp: number = 100let canli: boolean = true hp = hp - 30console.log(isim, hp, canli)
Çıktı
Ahri 70 true

isim: 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:

TipNe tutarÖrnek değerler
stringmetin"Ahri", ""
numberher sayı: tam, ondalıklı, eksi100, 3.5, -20
booleandoğru ya da yanlıştrue, false
undefinedhenüz bir değer yok (Ders 3)undefined
nullbilerek 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.

Sık hataerror 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.

temel.ts
let isim: string = "Ahri"let hp: number = 100let canli: boolean = true hp = "yetmiş"console.log(isim, hp, canli)
Çıktı
Ahri yetmiş true

Node 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:

Terminal — PowerShell
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:5

Type '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:

cikarim.ts
let altin = 300const koridor = "orta" altin = altin + 150altin = "bin"console.log(altin, koridor)
Çıktı
bin orta
Terminal — PowerShell
PS 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:5

Dosyada 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: string yazı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 = 300 gibi) 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:

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))
Çıktı
70090

Kalı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.

Sık hataerror 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.

hasar.ts
function iyiles(hp, miktar) {    return hp + miktar}
Terminal — PowerShell
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:5

Parameter '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.

Sık hataerror 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:

hasar.ts
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:

Terminal — PowerShell
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:

Terminal — PowerShell
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:

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))
Çıktı
hayattaundefined
Terminal — PowerShell
PS 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:

durum.ts
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))
Çıktı
hayattageçersiz can

Hiçbir şey döndürmeyen fonksiyon ve ok fonksiyonu

kritik.ts:

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))
Çıktı
[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 : number yazmasan da olurdu; TypeScript tipi 2'den çıkarır. Çağıran bu argümanı vermeyebilir.
  • void (boşluk): fonksiyon bir şey döndürmüyor. duyur yalnı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:

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))
Çıktı
Ahri: 100 can, 300 altın
  • type Sampiyon = { … }: "Sampiyon adında bir tip tanımlıyorum: isim metni, hp ve gold sayıları olan bir obje." type bir 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, tipininki Sampiyon.
  • 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 obje Sampiyon ş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:

sampiyon.ts
const lux: Sampiyon = { isim: "Lux", hp: 90 }const jinx: Sampiyon = { isim: "Jinx", hp: 80, gold: 250, mana: 300 }console.log(ahri.mana)
Terminal — PowerShell
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…: "gold alanı eksik ama Sampiyon'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; mana Sampiyon'da yok". Fazla bir alan çoğu zaman yazım hatasıdır (gold yerine glod); TypeScript bu yüzden durdurur.
  • TS2339: aşağıdaki kart.
Sık hataerror 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:

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")
Çıktı
Uzun Kılıç 350 altın

Yazımdaki tek fark: interface Esya { … }, arada = yok. Obje şekli için ikisi aynı işi görür. Farkları şunlar:

typeinterface
Obje şekli tanımlamakEvetEvet
Objeden başka tiplere ad vermek (type Koridor = "ust" | "orta")EvetHayır, yalnız obje
Aynı adla ikinci kez yazılırsaHata 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:

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))
Hata çıktısı
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.0

deniz 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:

Sık hataerror 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.

Terminal — PowerShell
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:

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 {    const takim = o.takimAdi ?? "takımsız"    return o.kullaniciAdi + " [" + takim.toLocaleUpperCase("tr") + "]"} console.log(kunye(arda))console.log(kunye(deniz))console.log(deniz)
Çıktı
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:

oyuncu.ts
console.log(deniz.kullaniciadi)
Terminal — PowerShell
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:18

TS2339'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:

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")
Çıktı
[ 'Garen', 'Ahri', 'Jinx' ]2 şampiyon ayakta
  • const takim: Sampiyon[]: dizinin her elemanı şekle uymalı. Birinde alan eksik ya da fazlaysa az önceki hataları alırsın.
  • map((s) => s.isim) ve filter((s) => s.hp > 0): s'ye tip yazmadık ve TS7006 da almadık. TypeScript takim'ın Sampiyon[] olduğunu bildiği için, geri çağırma fonksiyonunun (Ders 10) parametresinin Sampiyon olduğunu çıkarır.
  • canlilar'a da tip yazmadık: filter diziyi aynı tipte bıraktığı için o da Sampiyon[].
  • string[] yerine Array<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:

takim.ts
const lux = takim.find((s) => s.isim === "Lux")console.log(lux.hp)
Terminal — PowerShell
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:20

lux'ı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:

takim.ts
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:

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)
Çıktı
Garen envanteri: 800 altınKonum: 120 80
  • esyalar: Esya[]: Esya objelerinden 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ğeri 0'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:

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)
Çıktı
{ isim: 'Ahri', koridor: 'mid' }
Terminal — PowerShell
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:

id.ts
function idCoz(id: string | number): number {    return Number(id.trim())} console.log(idCoz(" 42 "))console.log(idCoz(7))
Hata çıktısı
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.0
Terminal — PowerShell
PS 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:2

Metin 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:

id.ts
function idCoz(id: string | number): number {    if (typeof id === "string") {        return Number(id.trim())    }    return id} console.log(idCoz(" 42 "))console.log(idCoz(7))
Çıktı
427

typeof 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.

id: string | number typeof id === "string" evet hayır if bloğunun içinde id: string id.trim() kullanılabilir bloktan sonra, return'ün altında id: number return id olduğu gibi
Şekil 39.2 Daraltma: 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:

TypeScript
const teemo = { isim: "Teemo", hp: 80 }console.log("isim" in teemo)console.log("tur" in teemo)
Çıktı
truefalse

Ders 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:

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 }))
Çıktı
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:

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))}
Çıktı
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 tur var ve her birinde değeri farklı bir sabit değer tipi. olay.tur === "oldurme" dediğin an TypeScript hangi şekilde olduğunu bilir: o blokta oldUren ve olen kullanılabilir, takim kullanılamaz.
  • Son durumu else if (olay.tur === "kule") değil, düz else ile yazdık: ilk iki koşul tutmadıysa geriye kule kalır ve TypeScript bunu bilir. else if yazsaydın TS2366 alırdın ("üç koşul da tutmazsa ne döner?"); TypeScript if zincirlerinde 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:

olay.ts
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" }))
Çıktı
undefined koridorunda kule yıkıldı
Terminal — PowerShell
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:13

Node 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:

olay.ts
    } 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:

veri.ts
const metin = '{"isim": "Teemo", "hp": 80}'const veri = JSON.parse(metin) console.log(veri.isim)console.log(veri.hpp.toFixed(1))
Hata çıktısı
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.0

JSON 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.toFixed gibi bir yazım hatası bile geçer; tip denetiminin bütün faydası o değer için biter.
  • Bulaşır. const hp = veri.hp yazarsan hp de any olur; onu döndüren fonksiyonun sonucu da. Tek bir any kodun içinde yayılır.
  • Sessizdir. TS7006 gibi bir uyarı vermez; aramazsan any olduğunu fark etmezsin.

Kural basit: kendi kodunda any yazma. Bir değerin tipini bilmiyorsan unknown yaz. veri.ts'yi şöyle değiştir:

veri.ts
const metin = '{"isim": "Teemo", "hp": 80}'const veri: unknown = JSON.parse(metin) console.log(veri.isim)
Çıktı
Teemo
Terminal — PowerShell
PS 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:4

Node 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: denetim kapalı unknown: önce kanıtla const veri: any const veri: unknown veri.hpp.toFixed(1) veri.hp tsc: hata yok, sessiz tsc: TS18046, önce denetle node: TypeError, çöktü denetledikten sonra güvenli
Şekil 39.3 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:

veri.ts
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")))
Çıktı
{ isim: 'Teemo', hp: 80 }nullnullnull
  • typeof veri !== "object" || veri === null: önce, bu bir obje mi? null'a ayrıca bakıyoruz, çünkü JavaScript'in eski bir kusuru yüzünden typeof null da "object" verir.
  • !("isim" in veri) || typeof veri.isim !== "string": isim alanı var mı, varsa metin mi? in denetiminden sonra TypeScript veri.isim'i okumana izin verir, ama tipi hâlâ unknown'dır; metin olduğunu typeof ile ayrıca kanıtlarız.
  • Üç denetimden geçen veriden yeni ve temiz bir Sampiyon kurulur. 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) ve null. 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.

hasar.ts: senin yazdığın function hasarVer(hp: number, hasar: number): number { Node tipleri boşlukla değiştirir Node'un çalıştırdığı JavaScript function hasarVer(hp········, hasar········)········ { ✓ Satır ve sütunlar yerinde: hata mesajı doğru yeri gösterir ✗ Tip denetimi yok: tipi yanlış kod da çalışır
Şekil 39.4 Node .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.
Sık hataSyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode

Ne 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:

koridor-enum.ts
enum Koridor {    Ust,    Orta,    Alt,} console.log(Koridor.Orta)
Terminal — PowerShell
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:

tsconfig.json
{    "compilerOptions": {        "target": "esnext",        "module": "nodenext",        "types": ["node"],        "strict": true,        "erasableSyntaxOnly": true,        "noEmit": true,        "skipLibCheck": true    }}
Terminal — PowerShell
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:1

erasableSyntaxOnly: "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 --noEmit bütün projeyi denetler. Sessizse temiz.
  • Çalıştırırken: node dosya.ts.
  • İstersen: npx tsc --noEmit --watch ile 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.

temel.ts:5:1 - error TS2322: Type 'string' is not assignable to type 'number'. 5 hp = "yetmiş" ~~ Found 1 error in temel.ts:5 temel.ts hatanın olduğu dosya 5:1 satır 5, sütun 1 TS2322 hata kodu: aramak için Found kaç hata, hangi dosyada 'string' senin verdiğin tip 'number' orada beklenen tip ~~ sorunlu yerin altı çizili 5 satır no ve satırın kopyası
Şekil 39.5 Bir tsc hata mesajının parçaları. Terminalde ilk iki satır tek satırdır; burada sığsın diye bölündü.

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: T tipinde x diye 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; null iç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:

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)
Terminal — PowerShell
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ı:

Terminal — PowerShell
PS C:\kod\tipler> npx tsc --noEmit...Found 3 errors in 2 files. Errors  Files     2  hasar.ts:5     1  oyuncu.ts:11

Node 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.

KodNe diyorİlk bakılacak yer
TS2322Bu değer bu tipe konamazDeğer mi yanlış, tip mi?
TS2345Bu argüman bu parametreye verilemezDeğeri kaynağında çevir
TS2339, TS2551Bu tipte böyle bir alan yokYazım; alan tipte var mı?
TS2741Zorunlu alan eksikObjeyi tamamla ya da alanı ? yap
TS2353Tipte olmayan fazla alanYazım hatası mı?
TS2554Argüman sayısı yanlışFonksiyonun tanımına bak
TS2366Her yolda return yokSınır değerlerini düşün
TS7006Parametrenin tipi yokTipi yaz
TS18046unknown değer denetlenmeden kullanılmışÖnce daralt
TS18048, TS18047undefined ya da null olabilirif, ?., ??

Sık hatalar

Tip hatalarının kartlarını bölümlerin içinde gördün. Bunlar araçla ilgili olanlar.

Sık hataThe term 'tsc' is not recognized

Ne 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.

Terminal — PowerShell
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 : CommandNotFoundException

Ders 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.

Sık hataThis is not the tsc command you are looking for

Ne 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:

Terminal — PowerShell
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):

Terminal — PowerShell
                 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.

Sık hatanpx tsc --noEmit hata yerine uzun bir yardım metni yazıyor

Ne 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:

Terminal — PowerShell
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.

Sık hataerror 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.

Terminal — PowerShell
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.

Sık hataerror 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:

selam.ts
const oyuncu = process.argv[2] ?? "misafir"console.log("Merhaba " + oyuncu)
Terminal — PowerShell
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:1

Node 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ç.

Görev 1

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:

Metin
Annie 4Annie 12Annie 36Annie 0Annie 0

Bitirince 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
birim.ts
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))
Çıktı
Annie 4Annie 12Annie 36Annie 0Annie 0

Son 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:

Terminal — PowerShell
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:24
Görev 2

Bü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.

buyu.ts✗ Yanlış
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))
Çıktı
falsefalse
Terminal — PowerShell
PS 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:6

Hepsini düzeltince sona bir sınır denemesi ekle: hazirMi(tutusturma, 180). Beklenen çıktı:

Metin
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
buyu.ts
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))
Çıktı
falsetruetrue

Son 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.

Görev 3

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) / olum iki basamakla (Ders 9).
  • killHizi(mac): dakika başına kill, iki basamakla ve sonuna kill/dk eklenmiş. Süre yoksa ya da 0 ise "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:

Metin
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
mac.ts
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)}`)}
Çıktı
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.

Görev 4

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:

  1. Odul tipini ayırt edici alanlı bir birleşim olarak yaz. Alanın adı tur, değerleri "altin", "birim", "esya". Yıldız yalnız 1 | 2 | 3 olabilsin.
  2. odulYaz(odul) her ödülü bir metne çevirsin.
  3. toplamAltin(oduller) bir ödül dizisindeki altınları toplasın; boş dizi ve altınsız dizi için 0 dö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ı:

Metin
3 altın2 yıldızlı Annieeşya: Uzun Kılıç5 altınToplam altın: 8Boş ganimet: 0Altınsız: 0

Bitirince 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
odul.ts
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" }]))
Çıktı
3 altın2 yıldızlı Annieeşya: Uzun Kılıç5 altınToplam altın: 8Boş ganimet: 0Altınsız: 0

Hatalı iki ödülü bir satır boşluk bırakıp const bozuk1: Odul = … ve const bozuk2: Odul = … diye eklediysen:

Terminal — PowerShell
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.

Görev 5

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, oyuncu metin değilse ya da puan sayı değilse o elemanı atla. Fazla alanlar sonuca girmesin.
  • any yazmak yok: JSON.parse'ın sonucunu unknown bir değişkene koy.

Şu dört denemeyle dene:

TypeScript
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ı:

Metin
[ { 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

Bozuk JSON için JSON.parse'ı try / catch içine al (Ders 13); catch'te return []. Değişkeni try'ın dışında let veri: unknown diye aç. Dizi mi diye Ders 32'de gördüğün Array.isArray(veri) ile sor.

İ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
skor.ts
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"))
Çıktı
[ { 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?

TypeScript
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?

TypeScript
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?

Metin
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?

TypeScript
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.

İşaret yalnızca bu tarayıcıda saklanır, kimseye gönderilmez.