العربية

استفد من قوة تأكيدات const في TypeScript لاستنتاج أنواع غير قابلة للتغيير، مما يعزز أمان الكود والتنبؤ به في مشاريعك. تعلم كيفية استخدامها بفعالية مع أمثلة عملية.

تأكيدات Const في TypeScript: استنتاج أنواع غير قابلة للتغيير لكود قوي

لغة TypeScript، وهي مجموعة شاملة من JavaScript، تجلب الأنواع الثابتة (static typing) إلى عالم تطوير الويب الديناميكي. إحدى ميزاتها القوية هي استنتاج الأنواع (type inference)، حيث يستنتج المترجم (compiler) تلقائيًا نوع المتغير. تأكيدات Const، التي تم تقديمها في TypeScript 3.4، تأخذ استنتاج الأنواع خطوة إلى الأمام، مما يمكّنك من فرض الثبات (immutability) وإنشاء كود أكثر قوة وقابلية للتنبؤ.

ما هي تأكيدات Const؟

تأكيدات Const هي طريقة لإخبار مترجم TypeScript بأنك تنوي أن تكون القيمة غير قابلة للتغيير (immutable). يتم تطبيقها باستخدام صيغة as const بعد قيمة حرفية (literal) أو تعبير. هذا يوجه المترجم لاستنتاج أضيق نوع ممكن (حرفي) للتعبير ووضع علامة readonly على جميع الخصائص.

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

فوائد استخدام تأكيدات Const

أمثلة عملية

مثال 1: الاستخدام الأساسي مع قيمة حرفية (Literal)

بدون تأكيد const، يستنتج TypeScript نوع message كـ string:


const message = "Hello, World!"; // Type: string

مع تأكيد const، يستنتج TypeScript النوع كسلسلة نصية حرفية "Hello, World!":


const message = "Hello, World!" as const; // Type: "Hello, World!"

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

مثال 2: استخدام تأكيدات Const مع المصفوفات

لنأخذ مصفوفة من الألوان:


const colors = ["red", "green", "blue"]; // Type: string[]

على الرغم من أن المصفوفة تم الإعلان عنها باستخدام const، لا يزال بإمكانك تعديل عناصرها:


colors[0] = "purple"; // No error
console.log(colors); // Output: ["purple", "green", "blue"]

بإضافة تأكيد const، يستنتج TypeScript المصفوفة كـ tuple (صف) من السلاسل النصية للقراءة فقط:


const colors = ["red", "green", "blue"] as const; // Type: readonly ["red", "green", "blue"]

الآن، محاولة تعديل المصفوفة ستؤدي إلى خطأ في TypeScript:


// colors[0] = "purple"; // Error: Index signature in type 'readonly ["red", "green", "blue"]' only permits reading.

هذا يضمن أن مصفوفة colors تظل غير قابلة للتغيير.

مثال 3: استخدام تأكيدات Const مع الكائنات

تمامًا مثل المصفوفات، يمكن أيضًا جعل الكائنات غير قابلة للتغيير باستخدام تأكيدات const:


const person = {
  name: "Alice",
  age: 30,
}; // Type: { name: string; age: number; }

حتى مع استخدام const، لا يزال بإمكانك تعديل خصائص كائن person:


person.age = 31; // No error
console.log(person); // Output: { name: "Alice", age: 31 }

إضافة تأكيد const تجعل خصائص الكائن readonly (للقراءة فقط):


const person = {
  name: "Alice",
  age: 30,
} as const; // Type: { readonly name: "Alice"; readonly age: 30; }

الآن، محاولة تعديل الكائن ستؤدي إلى خطأ في TypeScript:


// person.age = 31; // Error: Cannot assign to 'age' because it is a read-only property.

مثال 4: استخدام تأكيدات Const مع الكائنات والمصفوفات المتداخلة

يمكن تطبيق تأكيدات Const على الكائنات والمصفوفات المتداخلة لإنشاء هياكل بيانات غير قابلة للتغيير بشكل عميق. لنأخذ المثال التالي:


const config = {
  apiUrl: "https://api.example.com",
  endpoints: {
    users: "/users",
    products: "/products",
  },
  supportedLanguages: ["en", "fr", "de"],
} as const;

// Type:
// {
//   readonly apiUrl: "https://api.example.com";
//   readonly endpoints: {
//     readonly users: "/users";
//     readonly products: "/products";
//   };
//   readonly supportedLanguages: readonly ["en", "fr", "de"];
// }

في هذا المثال، كائن config، وكائن endpoints المتداخل، ومصفوفة supportedLanguages كلها تم تمييزها كـ readonly. هذا يضمن عدم إمكانية تعديل أي جزء من الإعدادات عن طريق الخطأ في وقت التشغيل.

مثال 5: تأكيدات Const مع أنواع الإرجاع للدوال

يمكنك استخدام تأكيدات const لضمان أن الدالة تُرجع قيمة غير قابلة للتغيير. هذا مفيد بشكل خاص عند إنشاء دوال مساعدة لا يجب أن تعدل مدخلاتها أو تنتج مخرجات قابلة للتغيير.


function createImmutableArray(items: T[]): readonly T[] {
  return [...items] as const;
}

const numbers = [1, 2, 3];
const immutableNumbers = createImmutableArray(numbers);

// Type of immutableNumbers: readonly [1, 2, 3]

// immutableNumbers[0] = 4; // Error: Index signature in type 'readonly [1, 2, 3]' only permits reading.

حالات الاستخدام والسيناريوهات

إدارة الإعدادات (Configuration)

تُعد تأكيدات const مثالية لإدارة إعدادات التطبيق. من خلال الإعلان عن كائنات الإعدادات الخاصة بك باستخدام as const، يمكنك ضمان بقاء الإعدادات متسقة طوال دورة حياة التطبيق. هذا يمنع التعديلات العرضية التي قد تؤدي إلى سلوك غير متوقع.


const appConfig = {
  appName: "My Application",
  version: "1.0.0",
  apiEndpoint: "https://api.example.com",
} as const;

تعريف الثوابت

تُعد تأكيدات const مفيدة أيضًا لتعريف الثوابت بأنواع حرفية محددة. هذا يمكن أن يحسن أمان الأنواع ووضوح الكود.


const HTTP_STATUS_OK = 200 as const; // Type: 200
const HTTP_STATUS_NOT_FOUND = 404 as const; // Type: 404

العمل مع Redux أو مكتبات إدارة الحالة الأخرى

في مكتبات إدارة الحالة مثل Redux، يُعد الثبات (immutability) مبدأً أساسيًا. يمكن أن تساعد تأكيدات const في فرض الثبات في الـ reducers ومنشئي الإجراءات (action creators)، مما يمنع حدوث طفرات (mutations) عرضية في الحالة.


// Example Redux reducer

interface State {
  readonly count: number;
}

const initialState: State = { count: 0 } as const;

function reducer(state: State = initialState, action: { type: string }): State {
  switch (action.type) {
    default:
      return state;
  }
}

التدويل (i18n)

عند العمل مع التدويل، غالبًا ما يكون لديك مجموعة من اللغات المدعومة ورموزها المحلية المقابلة. يمكن أن تضمن تأكيدات const بقاء هذه المجموعة غير قابلة للتغيير، مما يمنع الإضافات أو التعديلات العرضية التي قد تكسر تطبيق i18n الخاص بك. على سبيل المثال، تخيل دعم الإنجليزية (en)، والفرنسية (fr)، والألمانية (de)، والإسبانية (es)، واليابانية (ja):


const supportedLanguages = ["en", "fr", "de", "es", "ja"] as const;

type SupportedLanguage = typeof supportedLanguages[number]; // Type: "en" | "fr" | "de" | "es" | "ja"

function greet(language: SupportedLanguage) {
  switch (language) {
    case "en":
      return "Hello!";
    case "fr":
      return "Bonjour!";
    case "de":
      return "Guten Tag!";
    case "es":
      return "¡Hola!";
    case "ja":
      return "こんにちは!";
    default:
      return "Greeting not available for this language.";
  }
}

القيود والاعتبارات

بدائل لتأكيدات Const

بينما تُعد تأكيدات const أداة قوية لفرض الثبات، هناك طرق أخرى يمكنك أخذها في الاعتبار:

أفضل الممارسات

الخاتمة

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

من خلال دمج تأكيدات const بشكل استراتيجي في مشاريع TypeScript الخاصة بك، يمكنك كتابة كود أكثر موثوقية وقابلية للصيانة والتنبؤ. استغل قوة استنتاج الأنواع غير القابلة للتغيير وارتقِ بممارساتك في تطوير البرمجيات.