العربية

دليل شامل لتوقيعات الفهرس في TypeScript، مما يتيح الوصول الديناميكي للخصائص، وسلامة النوع، وهياكل البيانات المرنة للتطوير البرمجي الدولي.

توقيعات الفهرس في TypeScript: إتقان الوصول الديناميكي للخصائص

في عالم تطوير البرمجيات، غالبًا ما يُنظر إلى المرونة وسلامة النوع على أنهما قوتان متعارضتان. تقوم TypeScript، وهي مجموعة فائقة من JavaScript، بسد هذه الفجوة بأناقة، حيث تقدم ميزات تعزز كلاهما. إحدى هذه الميزات القوية هي توقيعات الفهرس. يتعمق هذا الدليل الشامل في تعقيدات توقيعات الفهرس في TypeScript، ويوضح كيف تتيح الوصول الديناميكي للخصائص مع الحفاظ على التحقق القوي من النوع. هذا أمر بالغ الأهمية بشكل خاص للتطبيقات التي تتفاعل مع البيانات من مصادر وتنسيقات متنوعة عالميًا.

ما هي توقيعات الفهرس في TypeScript؟

توفر توقيعات الفهرس طريقة لوصف أنواع الخصائص في كائن عندما لا تعرف أسماء الخصائص مسبقًا أو عندما يتم تحديد أسماء الخصائص ديناميكيًا. فكر فيها كطريقة لقول، "يمكن لهذا الكائن أن يحتوي على أي عدد من الخصائص من هذا النوع المحدد." يتم الإعلان عنها داخل واجهة أو اسم مستعار للنوع باستخدام الصيغة التالية:


interface MyInterface {
  [index: string]: number;
}

في هذا المثال، [index: string]: number هو توقيع الفهرس. دعنا نكسر المكونات:

لذلك، تصف MyInterface كائنًا حيث يجب أن تكون أي خاصية سلسلة نصية (على سبيل المثال، "age"، "count"، "user123") بقيمة رقمية. هذا يسمح بالمرونة عند التعامل مع البيانات التي لا تكون فيها المفاتيح الدقيقة معروفة مسبقًا، وهو أمر شائع في سيناريوهات تتضمن واجهات برمجة التطبيقات الخارجية أو المحتوى الذي تم إنشاؤه بواسطة المستخدم.

لماذا نستخدم توقيعات الفهرس؟

توقيعات الفهرس لا تقدر بثمن في سيناريوهات مختلفة. إليك بعض الفوائد الرئيسية:

توقيعات الفهرس قيد التنفيذ: أمثلة عملية

دعنا نستكشف بعض الأمثلة العملية لتوضيح قوة توقيعات الفهرس.

المثال 1: تمثيل قاموس للسلاسل النصية

تخيل أنك بحاجة إلى تمثيل قاموس تكون فيه المفاتيح هي رموز البلدان (على سبيل المثال، "US"، "CA"، "GB") والقيم هي أسماء البلدان. يمكنك استخدام توقيع فهرس لتحديد النوع:


interface CountryDictionary {
  [code: string]: string; // المفتاح هو رمز البلد (سلسلة)، القيمة هي اسم البلد (سلسلة)
}

const countries: CountryDictionary = {
  "US": "United States",
  "CA": "Canada",
  "GB": "United Kingdom",
  "DE": "Germany"
};

console.log(countries["US"]); // الإخراج: United States

// خطأ: لا يمكن تعيين النوع 'number' إلى النوع 'string'.
// countries["FR"] = 123;

يوضح هذا المثال كيف تفرض توقيعات الفهرس أن تكون جميع القيم سلاسل نصية. سيؤدي محاولة تعيين رقم إلى رمز بلد إلى خطأ في النوع.

المثال 2: التعامل مع استجابات واجهة برمجة التطبيقات

ضع في اعتبارك واجهة برمجة تطبيقات تُرجع ملفات تعريف المستخدمين. قد تتضمن واجهة برمجة التطبيقات حقولاً مخصصة تختلف من مستخدم لآخر. يمكنك استخدام توقيع فهرس لتمثيل هذه الحقول المخصصة:


interface UserProfile {
  id: number;
  name: string;
  email: string;
  [key: string]: any; // السماح بأي خاصية سلسلة أخرى بأي نوع
}

const user: UserProfile = {
  id: 123,
  name: "Alice",
  email: "alice@example.com",
  customField1: "Value 1",
  customField2: 42,
};

console.log(user.name); // الإخراج: Alice
console.log(user.customField1); // الإخراج: Value 1

في هذه الحالة، تسمح توقيعات الفهرس [key: string]: any لواجهة UserProfile بأن تحتوي على أي عدد من الخصائص الإضافية بالسلاسل النصية بأي نوع. هذا يوفر المرونة مع ضمان أن الخصائص id و name و email ذات نوع صحيح. ومع ذلك، يجب التعامل مع استخدام `any` بحذر، لأنه يقلل من سلامة النوع. ضع في اعتبارك استخدام نوع أكثر تحديدًا إن أمكن.

المثال 3: التحقق من صحة التكوين الديناميكي

افترض أن لديك كائن تكوين تم تحميله من مصدر خارجي. يمكنك استخدام توقيعات الفهرس للتحقق من أن قيم التكوين تتوافق مع الأنواع المتوقعة:


interface Config {
  [key: string]: string | number | boolean;
}

const config: Config = {
  apiUrl: "https://api.example.com",
  timeout: 5000,
  debugMode: true,
};

function validateConfig(config: Config): void {
  if (typeof config.timeout !== 'number') {
    console.error("Invalid timeout value");
  }
  // المزيد من التحقق...
}

validateConfig(config);

هنا، تسمح توقيعات الفهرس بأن تكون قيم التكوين سلاسل نصية أو أرقامًا أو قيمًا منطقية. يمكن لدالة validateConfig بعد ذلك إجراء فحوصات إضافية للتأكد من أن القيم صالحة للاستخدام المقصود.

توقيعات السلسلة النصية مقابل الأرقام

كما ذكرنا سابقًا، تدعم TypeScript توقيعات فهرس string و number. يعد فهم الاختلافات أمرًا بالغ الأهمية لاستخدامها بفعالية.

توقيعات فهرس السلاسل النصية

تسمح لك توقيعات فهرس السلاسل النصية بالوصول إلى الخصائص باستخدام مفاتيح السلاسل النصية. هذا هو النوع الأكثر شيوعًا من توقيعات الفهرس وهو مناسب لتمثيل الكائنات التي تكون فيها أسماء الخصائص سلاسل نصية.


interface StringDictionary {
  [key: string]: any;
}

const data: StringDictionary = {
  name: "John",
  age: 30,
  city: "New York"
};

console.log(data["name"]); // الإخراج: John

توقيعات فهرس الأرقام

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


interface NumberArray {
  [index: number]: string;
}

const myArray: NumberArray = [
  "apple",
  "banana",
  "cherry"
];

console.log(myArray[0]); // الإخراج: apple

ملاحظة مهمة: عند استخدام توقيعات فهرس الأرقام، ستقوم TypeScript تلقائيًا بتحويل الأرقام إلى سلاسل نصية عند الوصول إلى الخصائص. هذا يعني أن myArray[0] يعادل myArray["0"].

تقنيات توقيع الفهرس المتقدمة

بالإضافة إلى الأساسيات، يمكنك الاستفادة من توقيعات الفهرس مع ميزات TypeScript الأخرى لإنشاء تعريفات أنواع أقوى وأكثر مرونة.

الجمع بين توقيعات الفهرس والخصائص المحددة

يمكنك الجمع بين توقيعات الفهرس والخصائص المعرفة صراحةً في واجهة أو اسم مستعار للنوع. هذا يسمح لك بتعريف الخصائص المطلوبة بالإضافة إلى الخصائص المضافة ديناميكيًا.


interface Product {
  id: number;
  name: string;
  price: number;
  [key: string]: any; // السماح بالخصائص الإضافية من أي نوع
}

const product: Product = {
  id: 123,
  name: "Laptop",
  price: 999.99,
  description: "High-performance laptop",
  warranty: "2 years"
};

في هذا المثال، تتطلب واجهة Product خصائص id و name و price مع السماح أيضًا بالخصائص الإضافية من خلال توقيع الفهرس.

استخدام Generics مع توقيعات الفهرس

توفر Generics طريقة لإنشاء تعريفات أنواع قابلة لإعادة الاستخدام يمكنها العمل مع أنواع مختلفة. يمكنك استخدام Generics مع توقيعات الفهرس لإنشاء هياكل بيانات عامة.


interface Dictionary {
  [key: string]: T;
}

const stringDictionary: Dictionary = {
  name: "John",
  city: "New York"
};

const numberDictionary: Dictionary = {
  age: 30,
  count: 100
};

هنا، واجهة Dictionary هي تعريف نوع عام يسمح لك بإنشاء قواميس بأنواع قيم مختلفة. هذا يتجنب تكرار نفس تعريف توقيع الفهرس لأنواع بيانات مختلفة.

توقيعات الفهرس مع أنواع الاتحاد

يمكنك استخدام أنواع الاتحاد مع توقيعات الفهرس للسماح للخصائص بأنواع مختلفة. هذا مفيد عند التعامل مع البيانات التي يمكن أن تحتوي على أنواع متعددة محتملة.


interface MixedData {
  [key: string]: string | number | boolean;
}

const mixedData: MixedData = {
  name: "John",
  age: 30,
  isActive: true
};

في هذا المثال، تسمح واجهة MixedData بأن تكون الخصائص سلاسل نصية أو أرقامًا أو قيمًا منطقية.

توقيعات الفهرس مع أنواع الحرفية

يمكنك استخدام أنواع الحرفية لتقييد القيم المحتملة للفهرس. يمكن أن يكون هذا مفيدًا عندما تريد فرض مجموعة محددة من أسماء الخصائص المسموح بها.


type AllowedKeys = "name" | "age" | "city";

interface RestrictedData {
  [key in AllowedKeys]: string | number;
}

const restrictedData: RestrictedData = {
  name: "John",
  age: 30,
  city: "New York"
};

يستخدم هذا المثال نوع الحرفية AllowedKeys لتقييد أسماء الخصائص إلى "name" و "age" و "city". هذا يوفر تحققًا أكثر صرامة للنوع مقارنة بـ `string` فهرس عام.

استخدام نوع السجل `Record` المساعد

توفر TypeScript نوع أداة مساعد مدمج يسمى `Record` وهو أساسًا اختصار لتعريف توقيع فهرس بنوع مفتاح محدد ونوع قيمة محدد.


// يعادل: { [key: string]: number }
const recordExample: Record = {
  a: 1,
  b: 2,
  c: 3
};

// يعادل: { [key in 'x' | 'y']: boolean }
const xyExample: Record<'x' | 'y', boolean> = {
  x: true,
  y: false
};

يبسط نوع `Record` الصيغة ويحسن قابلية القراءة عندما تحتاج إلى هيكل أساسي يشبه القاموس.

استخدام الأنواع المعينة مع توقيعات الفهرس

تسمح لك الأنواع المعينة بتحويل خصائص نوع موجود. يمكن استخدامها بالاقتران مع توقيعات الفهرس لإنشاء أنواع جديدة بناءً على الأنواع الموجودة.


interface Person {
  name: string;
  age: number;
  email?: string; // خاصية اختيارية
}

// اجعل جميع خصائص Person مطلوبة
type RequiredPerson = { [K in keyof Person]-?: Person[K] };

const requiredPerson: RequiredPerson = {
  name: "Alice",
  age: 30,   // أصبح البريد الإلكتروني مطلوبًا.
  email: "alice@example.com" 
};

في هذا المثال، يستخدم النوع RequiredPerson نوعًا معينًا مع توقيع فهرس لجعل جميع خصائص واجهة Person مطلوبة. يزيل `-?` المعدل الاختياري من خاصية البريد الإلكتروني.

أفضل الممارسات لاستخدام توقيعات الفهرس

بينما توفر توقيعات الفهرس مرونة كبيرة، فمن المهم استخدامها بحكمة للحفاظ على سلامة النوع ووضوح الكود. إليك بعض أفضل الممارسات:

الأخطاء الشائعة وكيفية تجنبها

حتى مع فهم قوي لتوقيعات الفهرس، من السهل الوقوع في بعض الفخاخ الشائعة. إليك ما يجب الانتباه إليه:

اعتبارات التدويل والترجمة

عند تطوير برامج لجمهور عالمي، من الضروري مراعاة التدويل (i18n) والترجمة (l10n). يمكن أن تلعب توقيعات الفهرس دورًا في التعامل مع البيانات المترجمة.

المثال: نص مترجم

قد تستخدم توقيعات الفهرس لتمثيل مجموعة من نصوص اللغات المترجمة، حيث تكون المفاتيح هي رموز اللغات (على سبيل المثال، "en"، "fr"، "de") والقيم هي سلاسل النصوص المقابلة.


interface LocalizedText {
  [languageCode: string]: string;
}

const localizedGreeting: LocalizedText = {
  "en": "Hello",
  "fr": "Bonjour",
  "de": "Hallo"
};

function getGreeting(languageCode: string): string {
  return localizedGreeting[languageCode] || "Hello"; // الافتراضي إلى الإنجليزية إذا لم يتم العثور عليه
}

console.log(getGreeting("fr")); // الإخراج: Bonjour
console.log(getGreeting("es")); // الإخراج: Hello (الافتراضي)

يوضح هذا المثال كيف يمكن استخدام توقيعات الفهرس لتخزين واسترداد النصوص المترجمة بناءً على رمز اللغة. يتم توفير قيمة افتراضية إذا لم يتم العثور على اللغة المطلوبة.

الخلاصة

تعد توقيعات الفهرس في TypeScript أداة قوية للعمل مع البيانات الديناميكية وإنشاء تعريفات أنواع مرنة. من خلال فهم المفاهيم وأفضل الممارسات الموضحة في هذا الدليل، يمكنك الاستفادة من توقيعات الفهرس لتعزيز سلامة النوع وقابلية التكيف لكود TypeScript الخاص بك. تذكر استخدامها بحكمة، مع إعطاء الأولوية للتحديد والوضوح للحفاظ على جودة الكود. بينما تواصل رحلتك في TypeScript، فإن استكشاف توقيعات الفهرس سيفتح بالتأكيد إمكانيات جديدة لبناء تطبيقات قوية وقابلة للتطوير لجمهور عالمي. من خلال إتقان توقيعات الفهرس، يمكنك كتابة كود أكثر تعبيرًا وقابلية للصيانة وآمنًا من حيث النوع، مما يجعل مشاريعك أكثر قوة وقابلية للتكيف مع مصادر البيانات المتنوعة والمتطلبات المتطورة. احتضن قوة TypeScript وتوقيعات الفهرس الخاصة بها لبناء برامج أفضل، معًا.