🔑 اكتشف قوة keyof في TypeScript: كيف تستخرج مفاتيح الكائنات؟

اليوم سنتحدث عن أداة سحرية وبسيطة جداً في لغة TypeScript تسمى keyof. إذا كنت تتعامل مع الكائنات (Objects) وتريد التأكد من أنك تستخدم مفاتيح صحيحة وموجودة فعلياً داخل هذا الكائن، فأنت في المكان الصحيح.


🧐 ما هو عامل التشغيل keyof؟

ببساطة شديدة، keyof هو عامل تشغيل (Operator) يقوم بأخذ "نوع" (Type) معين لكائن، ويقوم بتحويله إلى "اتحاد من السلاسل النصية" (Union of Strings). هذه السلاسل النصية هي بالضبط أسماء المفاتيح (Keys) الموجودة داخل ذلك الكائن.

تخيلها كالتالي: بدلاً من أن تخبر TypeScript أن المتغير هو مجرد "نص" (string) قد يكون أي شيء، أنت تخبره: "هذا المتغير يجب أن يكون واحداً من أسماء المفاتيح الموجودة في هذا الكائن فقط". 🎯


🛠️ كيف يعمل keyof خطوة بخطوة؟

لنطبق ذلك بمثال عملي وبسيط جداً. لنفترض أن لدينا كائن يمثل "مستخدم" (User) يحتوي على اسم وعمر.

1. تعريف الواجهة (Interface)

أولاً، نقوم بتعريف شكل الكائن الخاص بنا:

interface User {
    firstName: string;
    lastName: string;
    age: number;
}

2. استخدام keyof لاستخراج المفاتيح

الآن، نريد إنشاء نوع جديد يحتوي فقط على المفاتيح المتاحة في User.

// هنا keyof تقوم بتحويل User إلى: "firstName" | "lastName" | "age"
type UserKeys = keyof User; 

// الآن المتغير userProperty يجب أن يكون واحداً من الثلاثة أعلاه
let userProperty: UserKeys;

userProperty = "firstName"; // ✅ صحيح
userProperty = "age";        // ✅ صحيح
userProperty = "email";      // ❌ خطأ! لأن email غير موجود في واجهة User

ماذا حدث هنا؟ 🧐 عندما كتبنا keyof User ، قامت TypeScript بالنظر إلى الواجهة User واستخرجت منها كل الأسماء الموجودة في اليسار (المفاتيح)، وجعلتها هي الخيارات الوحيدة المتاحة لهذا النوع.


🚀 مثال واقعي: دالة لجلب قيمة من الكائن

أكثر استخدام شائع لـ keyof هو عندما تريد كتابة دالة تستقبل كائناً واسم المفتاح الذي تريد جلب قيمته، وتريد التأكد من أن المفتاح الذي أدخله المستخدم موجود فعلاً في الكائن.

إليك هذا المثال البسيط:

interface Product {
    title: string;
    price: number;
    category: string;
}

const myProduct: Product = {
    title: "Gaming Mouse",
    price: 50,
    category: "Electronics"
};

// الدالة هنا تستخدم keyof Product للتأكد من أن المفتاح صحيح
function getProductValue(product: Product, key: keyof Product) {
    return product[key]; // جلب القيمة بناءً على المفتاح
}

// تجربة الدالة
console.log(getProductValue(myProduct, "title"));    // ✅ يعمل بنجاح (يطبع Gaming Mouse)
console.log(getProductValue(myProduct, "price"));     // ✅ يعمل بنجاح (يطبع 50)
// console.log(getProductValue(myProduct, "color"));  // ❌ خطأ برمجياً! لأن color ليس مفتاحاً في Product

شرح الكود:

  1. أنشأنا واجهة Product.
  2. في الدالة getProductValue جعلنا البارامتر الثاني key من نوع keyof Product.
  3. هذا يعني أن TypeScript ستمنعك من تمرير أي نص غريب لا يمثل مفتاحاً حقيقياً داخل Product 🛡️.

💡 لماذا نستخدم keyof بدلاً من string؟

قد تسأل نفسك: "لماذا لا أجعل نوع المفتاح مجرد string وانتهي من الأمر؟"

الجواب هو دقة النوع (Type Safety). لو استخدمت string:

  • لن ينبهك المحرر (VS Code) إذا أخطأت في كتابة اسم المفتاح.
  • قد يحاول الكود الوصول لمفتاح غير موجود، مما يؤدي لظهور undefined في تطبيقك.
  • مع keyof ، سيعطيك المحرر اقتراحات (Auto-complete) للمفاتيح المتاحة فوراً! ✨

🏁 ملخص سريع

  • keyof تأخذ نوع كائن وتعطيك اتحاداً من مفاتيحه.
  • تُستخدم لضمان أننا نتعامل مع مفاتيح موجودة فعلياً.
  • تمنع الأخطاء الإملائية عند الوصول إلى خصائص الكائنات.