تخطي إلى المحتوى الرئيسي

الأنواع الأساسية (Primitive Types)

مقدمة إلى الأنواع الأساسية في TypeScript

تُعدّ الأنواع الأساسية (Primitive Types) الركيزة الأولى والأكثر أهمية في لغة TypeScript، إذ تُمثّل اللبنات الأساسية التي يُبنى عليها كل كود برمجي. فعندما تبدأ بكتابة تطبيق باستخدام TypeScript، فإن أول ما ستصادفه هو تعريف المتغيرات وتحديد أنواع البيانات التي ستحملها. وهذه الأنواع الأساسية هي التي تُحدد طبيعة القيمة المخزنة في المتغير، سواء كانت نصاً أو رقماً أو قيمة منطقية، مما يمنح المُبرمج قدرة عالية على التحكم في سلوك البرنامج واكتشاف الأخطاء قبل تشغيله.

ما هي الأنواع الأساسية؟

الأنواع الأساسية هي أنواع بيانات بسيطة لا يمكن تفكيكها إلى أجزاء أصغر؛ فهي ليست كائنات (Objects) ولا مصفوفات (Arrays)، بل هي قيم خام تحمل معنى واحدًا واضحًا. تدعم لغة TypeScript سبعة أنواع أساسية رئيسية، ولكل منها دور محدد في بنية الشيفرة البرمجية:

  • string: يُستخدم لتمثيل النصوص والسلاسل المحرفية مثل أسماء المستخدمين أو العناوين أو الرسائل.
  • number: يُستخدم لتمثيل الأرقام الصحيحة والعشرية على حدٍّ سواء، وهو النوع الأساسي المعتمد للعمليات الحسابية.
  • boolean: يُمثّل القيم المنطقية الثنائية (true أو false)، ويُستخدم في الشروط والتحققات.
  • null: يُمثّل الغياب المتعمد لأي قيمة كائنية، أي أن المتغير مُعرَّف ومُفرَّغ عمداً.
  • undefined: يُشير إلى أن المتغير قد أُعلِن عنه لكنه لم يُسند إليه أي قيمة ابتدائية بعد.
  • symbol: يُولّد معرّفاً فريداً وغير قابل للتكرار، ويُستخدم كمفاتيح فريدة للخصائص في الكائنات.
  • bigint: يُستخدم لتمثيل الأعداد الصحيحة الضخمة جداً التي تتجاوز الحد الأقصى الآمن لنوع number (أي أكبر من 2^53 - 1).

أهمية الأنواع الأساسية في TypeScript

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

يوضح المثال التالي كيفية التصريح عن هذه الأنواع عملياً في TypeScript:

// تعريف متغير نصي
const userName: string = "أحمد المحترف";

// تعريف متغيرات رقمية
const age: number = 28;
const price: number = 19.99;

// تعريف متغير منطقي
const isActive: boolean = true;

// تعريف متغير لأرقام فائقة الحجم
const largeNumber: bigint = 9007199254740995n;

// تعريف معرّف فريد
const uniqueId: symbol = Symbol("id");

// تعريف متغيرات فارغة
const emptyValue: null = null;
const notAssigned: undefined = undefined;

أنواع القيم الرقمية في TypeScript

تتعامل TypeScript مع الأرقام بأسلوب مشتق من جافاسكريبت، حيث يتم تمثيل كافة الأرقام سواء كانت صحيحة (Integers) أو عشرية ذات فاصلة عائمة (Floats) تحت مظلة نوع أساسي واحد هو number، بالإضافة إلى النوع المخصص للأعداد الهائلة bigint.

الأعداد الصحيحة والعشرية (number)

يغطي النوع number في TypeScript جميع الأشكال العددية وفق معيار IEEE 754، ويشمل الأعداد الصحيحة، العشرية، الثنائية، والست عشرية:

// أعداد صحيحة وعشرية
let integerVal: number = 10;
let decimalVal: number = 10.5432;
let negativeVal: number = -42;

// تمثيلات بأنظمة عددية مختلفة
let binaryVal: number = 0b1010; // نظام ثنائي (10)
let hexVal: number = 0x7F;       // نظام ست عشري (127)

console.log(`${integerVal} و ${decimalVal}`);

الأعداد الصحيحة الكبيرة جداً (bigint)

عند الحاجة للتعامل مع أرقام حسابية أو معرّفات تتخطى القيمة 9007199254740991، يُستخدم النوع bigint بإضافة اللاحقة n إلى نهاية الرقم:

let hugeNumber: bigint = 9007199254740991000n;
let anotherBig: bigint = BigInt("900719925474099123456789");

console.log(hugeNumber);

أنواع النصوص (string) والقيم النصية

بعد التعرف على الأرقام، ننتقل إلى أحد أكثر الأنواع استخداماً: السلاسل النصية string. في TypeScript، تمثل النصوص الكلمات والفقرات والبيانات النصية، وتدعم ثلاثة أنماط للتعبير عنها: علامات التنصيص المزدوجة، الفردية، وسلاسل القوالب (Template Literals).

let firstName: string = "محمد";
let role: string = 'مهندس برمجيات';

// استخدام Template Literals لدمج النصوص والمتغيرات
let profileDescription: string = `الاسم: ${firstName}، الدور الوظيفي: ${role}`;

console.log(profileDescription);

الأنواع المرجعية (Reference Types) ومقارنتها بالأساسية

على عكس الأنواع الأساسية (Primitives) التي تُخزن قيمتها مباشرة في الذاكرة (Stack)، تُخزن الأنواع المرجعية (Reference Types) كمرجع يشير إلى موقع الكائن في الذاكرة (Heap). تشمل الأنواع المرجعية: الكائنات (Objects)، المصفوفات (Arrays)، والدوال (Functions).

  • الكائنات (Objects): تُمثّل هياكل بيانات تحتوي على أزواج من المفاتيح والقيم.
  • المصفوفات (Arrays): مجموعات مرتبة من العناصر من نوع محدد (مثل number[] أو string[]).
  • الدوال (Functions): كتل برمجية قابلة للاستدعاء ومحددة بتوقيع المدخلات والمخرجات.
// مصفوفة كنوع مرجعي
const numbers: number[] = [1, 2, 3, 4, 5];

// دالة تقبل معاملات محددة النوع وتُرجع قيمة
const greet = (name: string): string => {
  return `مرحباً، أنا ${name}`;
};

// كائن مرجعي
const userAccount: { id: number; username: string } = {
  id: 101,
  username: "code_developer"
};

أنواع القيم المنطقية (Boolean)

تُعدّ القيم المنطقية (Boolean Types) حجر الزاوية في بناء أي منطق برمجي سليم وفعّال. القيم المنطقية هي أساس اتخاذ القرارات والتحكم في تدفق مسار البرامج؛ فهي تقتصر حصرياً على حالتين ثنائيتين: true أو false.

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

يُمكنك التصريح عن النوع boolean صراحةً أو الاعتماد على نظام استنتاج الأنواع التلقائي (Type Inference) في TypeScript:

// تعريف صريح
let isLoggedIn: boolean = true;
let hasPermission: boolean = false;

// استنتاج تلقائي
let isCompleted = true; // يتم استنتاجه تلقائياً كـ boolean

if (isLoggedIn && !hasPermission) {
  console.log("المستخدم مسجل الدخول ولكنه لا يملك صلاحيات التعديل.");
}

العمليات المنطقية (Logical Operators)

تتيح TypeScript استخدام المعاملات المنطقية القياسية لدمج الشروط أو عكسها:

  • المعامل AND (&&): يُرجع true فقط إذا تحققت جميع الشروط.
  • المعامل OR (||): يُرجع true عند تحقق شرط واحد على الأقل.
  • المعامل NOT (!): يعكس القيمة المنطقية (يحول true إلى false والعكس).
let userIsAdmin: boolean = true;
let itemInStock: boolean = true;
let hasDiscount: boolean = false;

// دمج شروط منطقية
let canPurchase: boolean = itemInStock && (userIsAdmin || hasDiscount);
console.log(`إمكانية الشراء: ${canPurchase}`);

الأنواع والعمليات المنطقية هي جوهر اتخاذ القرارات في الأنظمة البرمجية. إتقان ضبطها يمنع التفرعات الشرطية غير المتوقعة ويوفر مسار تنفيذ واضح ومحكم.

أنواع القيم الفارغة والخاصة (null، undefined، void، never)

في بناء التطبيقات المعقدة، لا تكون كل المتغيرات ممتلئة بالبيانات دائماً. توفر TypeScript منظومة دقيقة للتعامل مع حالات الغياب أو الانعدام من خلال أربعة أنواع محورية: undefined، null، void، و never.

الفرق الجوهري بين undefined و null

  • undefined: يُشير إلى أن المتغير أُعلن عنه ولكن لم تُسند إليه قيمة، أو أن خاصية اختيارية في كائن غير معرّفة. هو الحالة الافتراضية لغياب القيمة.
  • null: يُشير إلى غياب مقصود ومتعمد للقيمة، ويُستخدم للدلالة على أن الحقل لا يحمل أي بيانات في الوقت الراهن (مثل نتيجة بحث فارغة).
// undefined: لم يُهيأ بعد
let unassignedVariable: string | undefined;
console.log(unassignedVariable); // undefined

// null: غياب مقصود
let queryResult: object | null = null;
console.log(queryResult); // null

التحقق الصارم من القيم الفارغة (Strict Null Checks)

عند تفعيل الخيار "strictNullChecks": true في ملف الإعدادات tsconfig.json، تمنع TypeScript إسناد null أو undefined لأي متغير إلا إذا تم التصريح عن ذلك صراحةً عبر أنواع الاتحاد (Union Types). هذا الإجراء يقضي نهائياً على أخطاء وقت التشغيل الشهيرة مثل Cannot read properties of undefined.

// تفعيل strictNullChecks يلزمنا بتحديد الاتحاد صراحة
let userBio: string | null = null;
userBio = "مطور تطبيقات سحابية"; // مسموح
userBio = null; // مسموح

// let title: string = null; // خطأ برمجي: Type 'null' is not assignable to type 'string'.

تقنيات التعامل الآمن: Optional Chaining و Nullish Coalescing

لتسهيل قراءة الشيفرة وتفادي تداخل جمل if المتعددة، توفر TypeScript أدوات حديثة للتعامل مع القيم الفارغة:

  • السلسلة الاختيارية (Optional Chaining – ?.): للوصول الآمن لخصائص الكائنات المتداخلة؛ فإذا كانت أي قيمة وسيطة null أو undefined، يُرجع التعبير undefined دون حدوث انهيار للبرنامج.
  • معامل الدمج الصفري (Nullish Coalescing – ??): لتوفير قيمة احتياطية افتراضية في حال كانت القيمة الأساسية حصراً null أو undefined.
interface UserSettings {
  profile?: {
    theme?: string;
  };
}

const settings: UserSettings = {};

// وصول آمن دون التسبب في خطأ
const currentTheme = settings.profile?.theme ?? "dark";
console.log(currentTheme); // سيطبع: dark

الأنواع المتقدمة: void و never

إلى جانب null و undefined، تُحدد TypeScript نوعين للمسارات غير المرجعة:

  • النوع void: يُستخدم مع الدوال التي تنفذ إجراءات معينة ولا تُرجع أي قيمة تفيد البرنامج (مثل دوال الطباعة في السجل).
  • النوع never: يُعبّر عن حالة لن تحدث إطلاقاً؛ إما لدالة تُطلق استثناءً يوقف البرنامج، أو لدخول الدالة في حلقة لا نهائية، أو للتحقق الشامل من استنفاد كافة خيارات الأنواع الموحدة (Exhaustive Checking).
// دالة من نوع void لا تُرجع بيانات
function logTrace(traceId: string): void {
  console.log(`Trace: ${traceId}`);
}

// دالة من نوع never توقف التنفيذ
function terminateProcess(message: string): never {
  throw new Error(`Critical Error: ${message}`);
}

// استخدام never في التحقق الشامل (Exhaustive Check)
type AppRole = "admin" | "editor";

function renderPanel(role: AppRole): void {
  switch (role) {
    case "admin":
      console.log("عرض لوحة الإدارة");
      break;
    case "editor":
      console.log("عرض لوحة التحرير");
      break;
    default:
      const exhaustiveCheck: never = role;
      throw new Error(`نوع غير مدعوم: ${exhaustiveCheck}`);
  }
}

أفضل الممارسات العملية لإدارة البيانات في قواعد البيانات والـ APIs

في التطبيقات الواقعية، تُعد معالجة غياب القيم ضرورة أساسية عند الربط مع واجهات برمجة التطبيقات (APIs) أو استعلامات قواعد البيانات:

  1. استخدام null للاستجابات الفارغة: من الممارسات الشائعة استخدام null كقيمة إرجاع عندما يفشل استعلام قاعدة البيانات في العثور على سجل معين، للإشارة الصريحة إلى أن المورد غير موجود دون إطلاق استثناء عشوائي.
  2. تحديد الحقول الاختيارية بـ undefined: عند تعريف واجهات البيانات (Interfaces) لنماذج الإدخال، حدد الحقول غير الإلزامية كخصائص اختيارية (email?: string).
  3. التضييق النوعي (Type Narrowing) قبل الحسابات: قبل إجراء أي عمليات حسابية أو استخدام دوال النصوص على متغيرات قد تكون فارغة، احرص على حراسة النوع (Type Guard) باستخدام جمل شرطية لتأكيد اكتمال البيانات.
interface ProductRecord {
  id: number;
  name: string;
  discountPrice?: number | null;
}

function calculateFinalPrice(product: ProductRecord, basePrice: number): number {
  // تضييق النوع للتحقق من وجود القيمة قبل استخدامها في الحسابات
  if (product.discountPrice !== undefined && product.discountPrice !== null) {
    return basePrice - product.discountPrice;
  }
  return basePrice;
}

إن الفهم الدقيق للأنواع الأساسية والتعامل المتزن مع القيم الفارغة في TypeScript يحوّل نظام الأنواع من مجرد أداة تنبيه إلى درع برمجي يحمي استقرار تطبيقاتك في بيئات الإنتاج الفعلية.


اكتشاف المزيد من كود التطور

اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.

MOHAMMAD ABU KASHREEF

MOHAMMAD ABU KASHREEF

محمد، مهندس برمجيات وصانع محتوى تقني، مؤسس كود التطور. أشارك خبرتي في البرمجة والتقنية بأسلوب عملي وتجارب واقعية، بهدف تبسيط المعرفة وبناء محتوى عربي موثوق وقابل للتطبيق.

اترك تعليقاً أو استفساراً