أدوات TypeScript العامة للاستخدام اليومي: دليل عملي

Frontend2026-09-21TryQuickToolBox

أنت تكتب دالة تعمل مع أي نوع، لكنك لا تريد فقدان أمان النوع. يمكنك استخدام any، لكن ذلك يبطل الغرض من TypeScript. تتيح لك الأنواع العامة كتابة كود يعمل مع أنواع متعددة مع الحفاظ على معلومات النوع. يوضح لك هذا الدليل كيفية استخدام الأنواع العامة في الكود اليومي دون تعقيد الأمور.

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

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

فكر في الأنواع العامة كمعاملات نوع. تمامًا كما تأخذ الدالة معاملات القيمة، تأخذ الدالة العامة معاملات النوع. على سبيل المثال، دالة الهوية:

function identity<T>(arg: T): T {
  return arg;
}

هنا، T هو معامل نوع. عند استدعاء identity<string>("hello")، يستنتج TypeScript أن T هو string، ونوع الإرجاع هو string. إذا مررت رقمًا، فإنه يعيد رقمًا. هذا أكثر دقة من استخدام any.

لماذا لا نستخدم any فقط؟

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

الدوال العامة في الممارسة

لنلقِ نظرة على سيناريو شائع: دالة تُرجع العنصر الأول من مصفوفة.

function firstElement<T>(arr: T[]): T | undefined {
  return arr[0];
}

بدون الأنواع العامة، قد تكتب function firstElement(arr: any[]): any، مما يفقد النوع. مع الأنواع العامة، إذا مررت string[]، فإن نوع الإرجاع هو string | undefined.

يمكنك أيضًا استخدام معاملات نوع متعددة. على سبيل المثال، دالة تربط مصفوفة بمصفوفة جديدة باستخدام دالة رد نداء:

function map<T, U>(arr: T[], fn: (item: T) => U): U[] {
  return arr.map(fn);
}

هذه هي الطريقة التي يتم بها كتابة Array.prototype.map في مكتبة TypeScript القياسية.

الواجهات العامة والأسماء المستعارة للنوع

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

interface Box<T> {
  value: T;
}

const stringBox: Box<string> = { value: "hello" };
const numberBox: Box<number> = { value: 42 };

هذا مفيد لاستجابات API، وإدارة الحالة، أو أي نوع حاوية.

يمكنك أيضًا توفير أنواع افتراضية:

interface ApiResponse<T = unknown> {
  data: T;
  status: number;
}

الآن ApiResponse بدون وسيطة نوع تعود إلى unknown.

قيود الأنواع العامة

أحيانًا تريد تقييد الأنواع التي يمكن استخدامها مع نوع عام. يمكنك استخدام الكلمة المفتاحية extends لإضافة قيد.

function getLength<T extends { length: number }>(arg: T): number {
  return arg.length;
}

الآن يجب أن يحتوي T على خاصية length. يمكنك استدعاء getLength("hello") أو getLength([1,2,3])، ولكن ليس getLength(42).

القيود قوية عند العمل مع كائنات تشترك في شكل مشترك.

استخدام الأنواع العامة مع الفئات

يمكن أن تكون الفئات عامة أيضًا. مثال شائع هو مجموعة عامة:

class Stack<T> {
  private items: T[] = [];

  push(item: T): void {
    this.items.push(item);
  }

  pop(): T | undefined {
    return this.items.pop();
  }
}

const stack = new Stack<number>();
stack.push(1);
stack.push(2);
const popped = stack.pop(); // number | undefined

هذا يضمن أنه لا يمكن دفع سوى الأرقام إلى مكدس الأرقام.

مثال من العالم الحقيقي: باعث أحداث آمن النوع

لنقم ببناء باعث أحداث بسيط يستخدم الأنواع العامة لربط أسماء الأحداث بأنواع الحمولة.

type EventMap = Record<string, any>;

class EventEmitter<T extends EventMap> {
  private listeners: { [K in keyof T]?: Array<(payload: T[K]) => void> } = {};

  on<K extends keyof T>(event: K, listener: (payload: T[K]) => void): void {
    if (!this.listeners[event]) {
      this.listeners[event] = [];
    }
    this.listeners[event]!.push(listener);
  }

  emit<K extends keyof T>(event: K, payload: T[K]): void {
    this.listeners[event]?.forEach(listener => listener(payload));
  }
}

// الاستخدام
interface MyEvents {
  login: { userId: string };
  logout: { userId: string };
}

const emitter = new EventEmitter<MyEvents>();
emitter.on('login', (payload) => {
  console.log(payload.userId); // string
});
emitter.emit('login', { userId: '123' }); // موافق
// emitter.emit('login', { userId: 123 }); // خطأ

يمنحك هذا النمط أمانًا كاملاً للنوع لأسماء الأحداث والحمولات، مما يقلل من أخطاء وقت التشغيل.

المزالق الشائعة وأفضل الممارسات

مقارنة: الأنواع العامة مقابل any مقابل أنواع الاتحاد

النهج أمان النوع المرونة حالة الاستخدام
الأنواع العامة عالي عالي مكونات قابلة لإعادة الاستخدام مع أنواع محفوظة
any لا يوجد عالي نماذج أولية سريعة، ترحيل JS
أنواع الاتحاد متوسط متوسط مجموعة محدودة من الأنواع المعروفة

تحقق الأنواع العامة توازنًا بين المرونة والأمان، مما يجعلها مثالية للمكتبات والأدوات المشتركة.

الأسئلة الشائعة

متى يجب استخدام الأنواع العامة بدلاً من أنواع الاتحاد؟

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

هل يمكنني استخدام الأنواع العامة مع دوال السهم؟

نعم، لكن الصياغة قد تكون صعبة في ملفات .tsx. يمكنك كتابة const identity = <T,>(arg: T): T => arg; مع فاصلة زائدة لتجنب غموض JSX.

كيف أقيد نوعًا عامًا ليقبل الكائنات فقط؟

استخدم T extends object أو T extends Record<string, unknown> لضمان أن T هو نوع كائن.

الأنواع العامة هي حجر الزاوية في نظام أنواع TypeScript. باستخدامها في الكود اليومي، يمكنك كتابة دوال وواجهات وفئات مرنة وآمنة في نفس الوقت. ابدأ بدوال عامة بسيطة، ثم أدرج القيود وأنماطًا أكثر تعقيدًا حسب الحاجة. لمزيد من أدوات المطورين، تحقق من JSON Formatter للتحقق من بيانات JSON وتنسيقها بسرعة.