Kodokon kodokon.com

الأنواع الحرفية والاتحادات المميَّزة

انمذج حالات تطبيقك باتحادات يتحقق منها المترجم نيابة عنك.

8 دقيقة · 3 أسئلة

افتح هذا الدرس في Kodokon

يقيّد النوع الحرفي القيمة إلى محتوى محدد بدقة: 'info' بدل string. إنه أساس واجهات API التي يستحيل إساءة استخدامها: المترجم يرفض أي قيمة خارج القائمة، ومحررك يقترح إكمالًا تلقائيًا.

TYPESCRIPT
type Level = "info" | "warn" | "error";

function log(level: Level, message: string): void {
  console.log(`[${level}] ${message}`);
}

log("info", "Server started");
// log("fatal", "Boom"); -> rejected by the compiler
اتحاد من الأنواع الحرفية يحصر القيم المسموح بها

الخطوة التالية هي تركيب أنواع كائنات تتشارك خاصية حرفية مشتركة، تُسمى العنصر المميِّز. فكل حالة من حالات استدعاء شبكي، مثلًا، تحمل فقط البيانات التي تخصها: الوصول إلى data أثناء التحميل مستحيل ببساطة.

TYPESCRIPT
type ApiState =
  | { status: "loading" }
  | { status: "success"; data: string[] }
  | { status: "error"; message: string };

function render(state: ApiState): string {
  switch (state.status) {
    case "loading":
      return "Loading...";
    case "success":
      return state.data.join(", ");
    case "error":
      return state.message;
  }
}
اتحاد مميَّز بواسطة الخاصية status

في كل case، يقوم TypeScript بـتضييق النوع: بعد case 'error'، توجد state.message ولا توجد state.data. هذه الآلية، المسماة narrowing، تحل محل الفحوص اليدوية الهشة. أضف حارس الشمولية لتُحكم إغلاق المنظومة كلها.

TYPESCRIPT
function assertNever(value: never): never {
  throw new Error("Unhandled case: " + String(value));
}

function label(state: ApiState): string {
  switch (state.status) {
    case "loading": return "In progress";
    case "success": return "Done";
    case "error": return "Failed";
    default: return assertNever(state);
  }
}
حارس الشمولية باستخدام النوع never

اختبار المعرفة

تأكّد من أنك تذكّرت النقاط الأساسية في هذا الدرس.

  1. في الاتحاد المميَّز، ما دور الخاصية المشتركة مثل status؟
    • تحسين الأداء أثناء التشغيل
    • تمكين المترجم من تضييق النوع في كل فرع
    • جعل الخاصية إلزامية في الـ JSON المستلَم
    • منع الخصائص المكررة
  2. مع type Level = 'info' | 'warn'، أي استدعاء لـ log(level, msg) يُترجَم بنجاح؟
    • log('debug', msg)
    • log('info', msg)
    • log(someString, msg) حيث someString من النوع string
  3. ما الغرض من دالة assertNever(value: never) في فرع default داخل switch؟
    • تسجيل الأخطاء في الإنتاج
    • تحويل حالة منسيّة إلى خطأ ترجمة
    • تحويل القيمة إلى never
    • إنهاء البرنامج بسرعة أكبر