- Konu sahibi
- #1
İlk bakışta
Aşağıdaki örnekte
Bunun nedeni TypeScript’in çalışma zamanında nesnenin gerçekten yalnızca bildirilmiş anahtarlara sahip olduğunu varsaymamasıdır. JavaScript nesnesi sonradan değiştirilebilir veya dışarıdan beklenmeyen bir anahtar alabilir. Bu nedenle
Nesneyi kod içinde siz oluşturduysanız ve anahtarların türünü biliyorsanız, anahtarları
Bu örnekte
Bu tür dönüşüm, nesnenin yalnızca kendi bildiğiniz anahtarları içerdiğinden emin olduğunuz durumlarda uygundur. Nesne dışarıdan geliyorsa veya çalışma zamanında ek özellik alabiliyorsa, dönüşümü sorgusuz kullanmak gerçekte olmayan bir anahtarı güvenliymiş gibi gösterebilir.
Aynı yaklaşımı her döngüde yeniden yazmak yerine, anahtarları nesnenin anahtar türüyle döndüren bir yardımcı işlev tanımlayabilirsiniz:
Burada
Ancak yardımcı işlev çalışma zamanında
Anahtarın yanında değere de ihtiyacınız varsa
Bu örnekte
Bu nedenle seçim, ihtiyaca göre yapılmalıdır:
Her anahtarın farklı bir değer türü varsa, yalnızca genel bir
Bu örnekte her koşul, ilgili anahtarın beklenen değer işlemiyle eşleştirilir. Rastgele bir anahtar adı oluşturup nesneye erişmek yerine anahtarları
Nesne kod içinde sabit ve kontrollü biçimde oluşturuluyorsa
Döngü sonunda TypeScript hata veriyorsa önce nesnenin türünü ve anahtar dizisinin gerçekten
Object.keys() kullanmak yeterli görünür; ancak TypeScript bu işlevin sonucunu genel olarak string[] olarak verir. Anahtarları nesnenin gerçek anahtar türleriyle güvenli biçimde dolaşmak için ya anahtarı keyof typeof nesne olarak daraltmalı ya da bunu yapan küçük bir yardımcı işlev kullanmalısınız. Böylece nes[key] erişimi güvenli kalır ve anahtarın değer türü doğru biçimde korunur.() neden doğrudan yeterli değildir?
Aşağıdaki örnekte
Object.keys(settings) sonucu çalışma zamanında anahtar adlarını içerir; fakat TypeScript bu dizinin elemanlarını yalnızca string kabul eder:
Kod:
const settings = {
theme: "dark",
pageSize: 20,
};
for (const key of Object.keys(settings)) {
// key: string
// settings[key] doğrudan güvenli kabul edilmez.
}
Bunun nedeni TypeScript’in çalışma zamanında nesnenin gerçekten yalnızca bildirilmiş anahtarlara sahip olduğunu varsaymamasıdır. JavaScript nesnesi sonradan değiştirilebilir veya dışarıdan beklenmeyen bir anahtar alabilir. Bu nedenle
Object.keys() dönüşünün otomatik olarak (keyof typeof settings)[] sayılmaması bilinçli bir güvenlik tercihidir.Bilinen bir nesnede güvenli dolaşım
Nesneyi kod içinde siz oluşturduysanız ve anahtarların türünü biliyorsanız, anahtarları
keyof typeof settings türüne dönüştürerek değer erişimini güvenli hâle getirebilirsiniz:
Kod:
const settings = {
theme: "dark",
pageSize: 20,
} as const;
type SettingKey = keyof typeof settings;
for (const key of Object.keys(settings) as SettingKey[]) {
const value = settings[key];
console.log(key, value);
}
Bu örnekte
key yalnızca "theme" | "pageSize" olabilir. Buna bağlı olarak settings[key] ifadesi de "dark" | 20 türünde değerlendirilir. as const kullanılmazsa anahtar türleri yine doğru biçimde çıkarılır; ancak değerler string ve number gibi daha genel türlere genişletilebilir.Bu tür dönüşüm, nesnenin yalnızca kendi bildiğiniz anahtarları içerdiğinden emin olduğunuz durumlarda uygundur. Nesne dışarıdan geliyorsa veya çalışma zamanında ek özellik alabiliyorsa, dönüşümü sorgusuz kullanmak gerçekte olmayan bir anahtarı güvenliymiş gibi gösterebilir.
Tekrar kullanılabilir güvenli anahtar yardımcı işlevi
Aynı yaklaşımı her döngüde yeniden yazmak yerine, anahtarları nesnenin anahtar türüyle döndüren bir yardımcı işlev tanımlayabilirsiniz:
Kod:
function typedKeys<T extends object>(object: T): Array<keyof T> {
return Object.keys(object) as Array<keyof T>;
}
const user = {
id: 42,
name: "Ayşe",
active: true,
};
for (const key of typedKeys(user)) {
const value = user[key];
console.log(`${String(key)}:`, value);
}
Burada
typedKeys(user) sonucu ("id" | "name" | "active")[] olarak görülür. user[key] erişimi de nesnenin tanımlı özelliklerinden biriyle sınırlanır.Ancak yardımcı işlev çalışma zamanında
Object.keys() davranışını değiştirmez; yalnızca TypeScript’e dönen anahtarların keyof T ile uyumlu olduğunu bildirir. Bu nedenle bu işlevi, nesnenin gerçek anahtarlarının TypeScript türüyle uyumlu olduğu kontrollü kodlarda kullanın. Güvenilmeyen JSON verisini önce doğrulamadan bu türü kesin gerçek gibi kabul etmeyin.Anahtar ve değeri birlikte dolaşmak
Anahtarın yanında değere de ihtiyacınız varsa
Object.entries() kullanabilirsiniz. Bu işlevde de TypeScript çoğu durumda anahtarları genel string, değerleri ise genel bir tür olarak görür. Bilinen bir nesnede girişleri türlendirmek için küçük bir yardımcı işlev kullanılabilir:
Kod:
function typedEntries<T extends object>(object: T): Array<[keyof T, T[keyof T]]> {
return Object.entries(object) as Array<[keyof T, T[keyof T]]>;
}
const prices = {
book: 120,
pen: 25,
};
for (const [key, value] of typedEntries(prices)) {
console.log(key, value);
}
Bu örnekte
key "book" | "pen", value ise number türündedir. Fakat bu genel imzada belirli bir anahtar ile onun kendine özgü değer türü arasındaki ilişki her zaman korunmaz. Örneğin farklı anahtarların farklı değer türleri varsa, value tüm olası değer türlerinin birleşimi olarak görülebilir.Bu nedenle seçim, ihtiyaca göre yapılmalıdır:
| İhtiyaç | Uygun yaklaşım | Dikkat edilmesi gereken |
|---|---|---|
| Yalnız anahtarları dolaşmak | () ve keyof türü | Tür dönüşümü nesnenin çalışma zamanı yapısıyla uyumlu olmalıdır. |
| Anahtar ve değeri birlikte almak | () ve türlendirilmiş yardımcı işlev | Anahtar-değer ilişkisi her zaman ayrı ayrı korunmayabilir. |
| Güvenilmeyen dış veri | Önce şema veya çalışma zamanı doğrulaması | TypeScript türü tek başına gelen veriyi doğrulamaz. |
Belirli bir anahtara göre işlem yaparken daraltma
Her anahtarın farklı bir değer türü varsa, yalnızca genel bir
keyof döngüsü bazen yeterli olmaz. TypeScript, bir birleşim türündeki anahtar ile değerin hangi çifte ait olduğunu her zaman otomatik olarak ilişkilendiremez. Böyle bir durumda anahtarları açıkça kontrol ederek değeri daraltabilirsiniz:
Kod:
const product = {
name: "Kalem",
stock: 15,
available: true,
};
for (const key of typedKeys(product)) {
const value = product[key];
if (key === "name") {
console.log(value.toUpperCase());
} else if (key === "stock") {
console.log(value.toFixed(0));
} else {
console.log(value ? "Satışta" : "Tükendi");
}
}
Bu örnekte her koşul, ilgili anahtarın beklenen değer işlemiyle eşleştirilir. Rastgele bir anahtar adı oluşturup nesneye erişmek yerine anahtarları
keyof ile sınırlamak, yazım hatalarını derleme aşamasında yakalamaya yardımcı olur.Güvenli kullanım için kısa karar kuralı
Nesne kod içinde sabit ve kontrollü biçimde oluşturuluyorsa
Object.keys(object) as Array<keyof typeof object> veya typedKeys() kullanılabilir. Anahtarlarla birlikte değerleri almanız gerekiyorsa typedEntries() benzeri bir yardımcı işlev tercih edin. Nesne API, dosya veya kullanıcı girdisi gibi dış bir kaynaktan geliyorsa önce çalışma zamanında doğrulayın; keyof yalnızca derleyiciye bilgi verir, gelen verinin gerçekten bu yapıya sahip olduğunu kanıtlamaz.Döngü sonunda TypeScript hata veriyorsa önce nesnenin türünü ve anahtar dizisinin gerçekten
keyof ile sınırlandırılıp sınırlandırılmadığını kontrol edin. Hata yalnızca anahtar-değer ilişkisinin korunmamasından kaynaklanıyorsa, değeri ilgili anahtar üzerindeki koşuldan sonra kullanın veya nesneyi anahtar-değer ilişkisini taşıyan bir birleşim türüyle modelleyin.