keyof bir nesne tipi alır ve özellik adlarının union'ını üretir. Aşağıdaki keyof User, "id" | "name" | "email" tipidir; bu yüzden o tipteki bir değişken yalnızca bu üç string'den birini tutabilir.
keyof yalnızca tip sisteminde vardır. Kod derlendiğinde silinir, dolayısıyla çalışma zamanında hiçbir şeyi kontrol etmez. Size verdiği şey, bir anahtarın gerçek bir özelliği adlandırdığına dair derleme zamanı garantisidir: interface'teki email adını değiştirin, keyof User olarak tiplenmiş her "email" bir hataya dönüşür.
keyof typeof: Düz Bir Nesnenin Anahtarları
keyof değerler üzerinde değil tipler üzerinde çalışır. Değer olarak yazdığınız bir nesne için önce typeof ile tipini alın, ardından anahtarlarını çıkarın:
İçten dışa doğru okuyun: typeof colors, { red: string; green: string; blue: string } tipidir ve onun keyof sonucu anahtar union'ıdır. typeof olmadan keyof colors yazmak error TS2749: 'colors' refers to a value, but is being used as a type here. Did you mean 'typeof colors'? ile başarısız olur.
Bir arama tablosundan union türetmenin olağan yolu budur: nesneye bir renk ekleyin, Color tipi de onunla birlikte büyür. typeof operatörünün ikinci bir, çalışma zamanı anlamı da vardır; typeof sayfası ikisini de anlatıyor.
Generics ile Tipli Özellik Erişimi
keyof operatörünün en yaygın kullanımı bir generic kısıtlamasıdır. K extends keyof T "K, T'nin anahtarlarından biridir" der ve T[K] o anahtardaki özelliğin tipidir:
İkinci tip parametresi önemlidir. K olmadan yalnızca key: keyof T kullanılırsa dönüş tipi T[keyof T], yani tüm özellik tiplerinin union'ı olur (burada string | number | boolean); bu yüzden title.toUpperCase(), error TS2339: Property 'toUpperCase' does not exist on type 'string | number | boolean' ile başarısız olurdu. Tam anahtarı K içinde yakalamak, tam özellik tipini korur. T[K] bir indeksli erişim tipidir ve indeksli erişim tipleri sayfasında anlatılır.
Düz Bir string ile İndekslemek
Bir nesneyi başka bir yerden gelen bir string ile indekslediğinizde çok yaygın bir hata ortaya çıkar:
Derleyici şunu yazdırır:
index.ts(10,10): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Settings'.
No index signature with a parameter of type 'string' was found on type 'Settings'.
read fonksiyonuna "colour" dahil herhangi bir string ulaşabilir ve Settings bu anahtar hakkında hiçbir şey söylemez. İki çözüm var: yalnızca gerçek anahtarları kabul edin ya da bilinmeyen bir string'i kullanmadan önce kontrol edin.
name is keyof Settings bir tip yüklemidir (type predicate): fonksiyon true döndürdüğünde TypeScript if içindeki input değerini bir anahtar olarak ele alır. Yüklemler type guard'lar sayfasında ayrıntılı olarak anlatılıyor.
İndeks İmzalarıyla keyof: string | number
İndeks imzası olan bir tip için keyof indeks tipini döndürür ve bir string indeks imzası yalnızca string değil, string | number verir:
JavaScript her sayısal özellik anahtarını string'e çevirir, bu yüzden scores[42] ve scores["42"] aynı özelliktir. TypeScript bunu number tipini ekleyerek modeller. Çıktı ayrıca bir JavaScript kuralını da gösteriyor: tam sayıya benzeyen anahtarlar diğer string anahtarlardan önce, artan sırayla listelenir. Generic bir fonksiyonun yalnızca string anahtarlara ihtiyacı olduğunda Extract<keyof T, string> ya da string & keyof T yazın; Exclude ve Extract için ayrı bir sayfa var.
Bir Bakışta keyof Sonuçları
| Tip | keyof sonucu |
|---|---|
{ id: number; name: string } | "id" | "name" |
{ [key: string]: number } | string | number |
{ [index: number]: string } | number |
{} | never |
any | string | number | symbol |
{ a: 1; b: 2 } | { a: 3; c: 4 } | "a" (her üyede olan anahtarlar) |
{ a: 1 } & { c: 4 } | "a" | "c" (herhangi birinin anahtarları) |
string[] | number ve her dizi metodunun adı ("length", "push", ...) |
Union ve intersection satırları ilk bakışta ters görünür. Bir union tipindeki değer üyelerden herhangi biri olabilir, bu yüzden yalnızca her ikisinde de bulunan anahtarlar güvenlidir. Bir intersection değeri ise ikisindeki her şeye sahiptir, dolayısıyla tüm anahtarlara sahiptir.
Object.keys Neden string[] Döndürür
Object.keys(obj) her zaman string[] olarak tiplenir, asla (keyof T)[] olarak değil. Nedeni yapısal tiplemedir: bir değer, bildirilen tipinden daha fazla özellik taşıyabilir.
p değeri Point olarak tiplenmiştir, ama çalışma zamanında bir z anahtarı vardır. Object.keys, ("x" | "y")[] vaat etseydi, buna güvenen kod p için yanlış olurdu. Cast, kendiniz oluşturduğunuz nesne literalleri için güvenlidir; dışarıdan gelen nesneler için anahtarları string olarak tutun ve kontrol edin.
Mapped Type'larda keyof
keyof aynı zamanda yeni bir tip oluşturmak için bir tipin anahtarları üzerinde dolaşmanın yoludur. Yerleşik Partial ve Readonly yardımcı tipleri bu şekilde yazılmıştır:
type MyPartial<T> = { [K in keyof T]?: T[K] };
type MyReadonly<T> = { readonly [K in keyof T]: T[K] };
interface User {
id: number;
name: string;
}
type UserDraft = MyPartial<User>; // { id?: number; name?: string }
[K in keyof T] her anahtarı ziyaret eder, T[K] ise o anahtardaki özellik tipini okur. Mapped type'ların belirleyicileri ve anahtar yeniden eşlemeyi anlatan ayrı bir sayfası var.
Sıkça Sorulan Sorular
TypeScript'te keyof ne işe yarar?
keyof T, T tipinin özellik adlarından bir union üretir. interface User { id: number; name: string } için keyof User, "id" | "name" olur. Yalnızca tipler üzerinde, derleme zamanında çalışır ve hiç JavaScript üretmez.
TypeScript'te keyof typeof nedir?
keyof bir tipe ihtiyaç duyar, ama const colors = { red: "#f00" } gibi düz bir nesne bir değerdir. typeof colors değeri tipine çevirir, keyof typeof colors ise ardından anahtarlarının union'ını verir, burada "red". keyof colors yazmak TS2749 hatasıyla başarısız olur.
keyof neden string | number döndürür?
Tipte { [key: string]: number } gibi bir string indeks imzası olduğunda. JavaScript sayısal özellik anahtarlarını string'e çevirir, bu yüzden obj[42] de geçerli bir erişimdir ve TypeScript anahtar tipine number ekler. Yalnızca string anahtarları istiyorsanız Extract<keyof T, string> ya da string & keyof T kullanın.
Object.keys neden (keyof T)[] yerine string[] döndürür?
Çünkü bir nesne, tipinin listelediğinden daha fazla özellik taşıyabilir: fazladan bir alanı olan bir değer daha dar bir tipe atanabilir. Sonucu (keyof T)[] olarak tiplemek bu nesneler için yanlış olurdu. Nesnenin tam olarak bildirilen anahtarlara sahip olduğunu biliyorsanız cast edin: Object.keys(obj) as (keyof typeof obj)[].
"Element implicitly has an 'any' type because expression of type 'string' can't be used to index type" hatasını nasıl düzeltirim?
İndeks düz bir string ve nesne tipinde string indeks imzası yok. Parametreyi string yerine keyof YourType olarak tipleyin, ya da string'i önce onu keyof YourType tipine daraltan bir type guard ile kontrol edin, ya da nesne gerçekten her anahtarı kabul ediyorsa ona bir indeks imzası veya Record<string, V> tipi verin.