Bir ifadeden sonra gelen ünlem işareti, value!, non-null assertion operatörüdür. Tipten null ve undefined tiplerini çıkarır, böylece bir number | undefined bir number olarak kullanılabilir. Bu derleyiciye verilen bir sözdür, bir kontrol değildir: çalışma zamanında hiçbir şey olmaz.
! olmadan tea.toFixed(2), TS18048 hatasıdır: 'tea' is possibly 'undefined'. ! ile kod derlenir, çünkü derleyiciye anahtarın var olduğunu söylediniz.
x! Çalışma Zamanında Ne Yapar: Hiçbir Şey
! çıktıdan silinir. prices.get("coffee")! için derlenmiş JavaScript sadece prices.get("coffee") olur. Assertion yanlışsa hata daha sonra, eksik değerin ilk kullanıldığı yerde ortaya çıkar:
Program Cannot read properties of undefined (reading 'toFixed') yazdırır. Çökme ! işaretinden sonraki satırda olur; gerçek kodda çok daha uzakta olabilir: undefined bir nesnede saklanıp başka bir dosyada patlayabilir. ! işaretini riskli yapan bu mesafedir.
Kesin Atama: let x!: T
Aynı sembolün bir bildirimde ilişkili bir anlamı vardır. TypeScript bir değişkenin okunmadan önce atanıp atanmadığını izler ve başka bir fonksiyonun içinde yapılan bir atamayı takip edemez:
index.ts(9,13): error TS2454: Variable 'config' is used before being assigned.
let config!: { port: number }; bir kesin atama assertion'ıdır: "bu, her okumadan önce atanacak". Hatayı düzeltir, x! ile aynı püf noktasıyla: init() bir gün atlanırsa okuma undefined alır. Kodu yeniden yapılandırmak genellikle daha iyidir; örneğin init nesneyi döndürecek şekilde const config = init();.
Sınıf Özellikleri: prop!: T
strictPropertyInitialization (strict kapsamında) açıkken her sınıf özelliği, bildiriminde ya da constructor içinde başlatılmalıdır. Aksi halde TS2564 alırsınız: Property 'socket' has no initializer and is not definitely assigned in the constructor. Bir özellik daha sonra bir metot veya bir framework tarafından ayarlanıyorsa prop!: T derleyiciye onu kabul etmesini söyler:
İlk console.log boşluğu gösteriyor: tip socket özelliğinin her zaman var olduğunu söylüyor, ama open() öncesinde undefined. O noktada c.socket.send çağırmak derlenir ve hata fırlatır. Özellik gerçekten eksik olabiliyorsa onu socket?: ... olarak tanımlayıp kontrol edin ya da nesneyi constructor içinde oluşturun. prop! kullanımının standart pratik olduğu ana yer, bir özelliği oluşturma sonrasında dolduran bir framework'tür: Angular'ın @ViewChild(...) child!: ChildDirective ifadesi (ngAfterViewInit çalışmadan önce ayarlanır) ya da sütunlarını kütüphanenin bir satırı yüklerken doldurduğu ORM entity sınıfları (MikroORM'un dokümantasyonu @Property() title!: string yazar).
Daha Güvenli Alternatifler
Çoğu ! işareti, derleyicinin kontrol ettiği bir şeyle ya da doğru yerde yüksek sesle başarısız olan bir kontrolle değiştirilebilir:
İki yardımcı da ! gibi tipi daraltır, ama yanlış bir varsayım başka bir yerde bir TypeError yerine anında missing HOST üretir. assertDefined bir assertion fonksiyonudur (asserts value is ...): çağrıdan sonra derleyici host değerini bir string olarak ele alır. Daha fazla kalıp type guard'lar sayfasında.
| Bunun yerine | Bunu yazın | Değer eksik olduğunda ne olur |
|---|---|---|
user!.name | if (user) { user.name } | blok atlanır |
user!.name | user?.name | undefined |
count! | count ?? 0 | varsayılan kullanılır |
map.get(k)! | must(map.get(k), "k") | o satırda açık bir hata |
let x!: T | const x = compute() | ters gidecek bir şey yok |
Diğer Ünlem İşaretleri
! bulunduğu yere göre farklı anlamlar taşır:
| Kod | Anlamı |
|---|---|
value! (bir ifadeden sonra) | non-null assertion, yalnızca TypeScript |
let x!: T, prop!: T | kesin atama assertion'ı, yalnızca TypeScript |
!value (bir ifadeden önce) | mantıksal DEĞİL, düz JavaScript |
!!value | boolean'a çevirir, düz JavaScript |
a !== b, a != b | eşitsizlik, düz JavaScript |
Yalnızca ilk ikisi derleme zamanında silinir. !value ve !!value çalışma zamanında çalışır ve bir boolean döndürür.
Sıkça Sorulan Sorular
TypeScript'te bir değişkenden sonraki ünlem işareti ne anlama gelir?
value!, non-null assertion operatörüdür. Derleyiciye value değerinin null veya undefined olmadığını söyler, böylece tipi bu iki üyeyi kaybeder: string | undefined tipi string olur. Üretilen JavaScript'ten silinir ve hiçbir çalışma zamanı kontrolü eklemez; yanılıyorsanız program daha sonra bir TypeError ile başarısız olur.
TypeScript'te ! ile ? arasındaki fark nedir?
x! değerin var olduğunu iddia eder ve size kontrolsüz olarak null olmayan tipi verir. x?.y ise çalışma zamanında kontrol eder: x değeri null veya undefined ise durur ve undefined döndürür. Bir bildirimde name?: string bir özelliği opsiyonel yapar, name!: string ise zorunlu bir özelliğin derleyicinin göremediği bir yerde atanacağını söyler.
let x!: string ne anlama gelir?
Bir kesin atama assertion'ıdır (definite assignment assertion). Derleyiciye, kanıtlayamasa bile (örneğin atama başka bir fonksiyonun içinde yapılıyorsa) değişkenin okunmadan önce atanacağını söyler. Bu olmadan değişkeni okumak TS2454 hatasıdır, Variable 'x' is used before being assigned.
"has no initializer and is not definitely assigned in the constructor" hatasını nasıl düzeltirim?
Bu, strictPropertyInitialization kaynaklı TS2564 hatasıdır. Özelliğe bir başlangıç değeri verin, constructor içinde atayın, opsiyonel yapın (prop?: T) ya da bir framework veya bir init metodu onu kullanmadan önce gerçekten ayarlıyorsa prop!: T yazın. ! son seçenektir, çünkü bu sözü hiçbir şey kontrol etmez.
Non-null assertion operatörü kötü bir pratik mi?
Yanlış değildir, ama her ! kontrolsüz bir iddiadır. @typescript-eslint/no-non-null-assertion gibi lint ayarları onu işaretler. Daraltan bir kontrolü (if (x), x ?? fallback, x?.y) ya da açık bir hata fırlatan bir yardımcıyı tercih edin. ! işaretini değerin derleyicinin izleyemediği bir mantıkla garanti edildiği yerlere saklayın.