Menu
flag Ar iconالعربيةdown icon

Map في TypeScript: Map<K, V> وget وset وhas والتكرار

كيف تستخدم Map في TypeScript: إنشاء Map<K, V> بأنواع محددة، ولماذا تعيد get النوع V | undefined، وset وhas وdelete، والتكرار بترتيب الإدراج، والمفاتيح من نوع كائن، والتحويل من الكائنات وJSON وإليها، والفرق بين Map والكائن وRecord، وتحديد أنواع array.map().

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

الـ Map في TypeScript هي Map المدمجة في JavaScript مع مفاتيح وقيم محددة الأنواع: Map<string, number> تربط نصوصًا بأرقام. أنشئها بـ new Map<K, V>()، ثم استخدم set وget وhas وdelete. تعيد get النوع V | undefined، لأن المفتاح قد يكون غير موجود.

وسائط النوع هي ما يجعل الـ Map مفيدة في TypeScript: كل استدعاء لـ set يُفحص، وكل get يعيد نوع القيمة. السطر الأخير خطأ ترجمة (TS2345)، ويُبقي @ts-expect-error الكتلة قابلة للتشغيل.

تتناول هذه الصفحة المجموعة Map. إذا كنت تبحث عن array.map() فستجده في القسم الأخير.

إنشاء Map

تأتي الأنواع من وسائط النوع، أو من العناصر الأولية، أو من تحديد نوع صريح. العناصر الأولية مصفوفة من tuples بالشكل [key, value]، أو أي شيء آخر ينتجها.

فخّان في الاستنتاج:

  • new Map() دون وسائط نوع ودون عناصر نوعها Map<any, any>. لا يُفحص أي شيء تضعه فيها أو تأخذه منها. اكتب دائمًا new Map<K, V>().
  • العناصر ذات أنواع القيم المختلفة لا تُستنتج كـ union. new Map([["a", 1], ["b", "x"]]) خطأ TS2769 (No overload matches this call). اكتب النوع: new Map<string, number | string>([...]).

get تعيد V | undefined

لا تستطيع الـ Map أن تضمن وجود مفتاح، لذلك نوع get هو V | undefined. مع strict يجب أن تتعامل مع undefined قبل استخدام القيمة كـ V:

index.ts(4,7): error TS2322: Type 'number | undefined' is not assignable to type 'number'.
  Type 'undefined' is not assignable to type 'number'.

الحلول، من الأكثر شيوعًا إلى الأقل:

لا يتذكر TypeScript أن has أعادت true عندما تستدعي get لاحقًا. فحص نتيجة get مباشرة أقصر وآمن في الوقت نفسه. تأكيد عدم القيمة الفارغة، stock.get("apples")!، يُسكت الخطأ لكنه لا يحميك إذا كان المفتاح غير موجود.

دوال Map وأنواعها

العضوالنوع في Map<K, V>ملاحظات
new Map<K, V>(entries?)Map<K, V>entries: كائن قابل للتكرار من [K, V]
set(key, value)thisيضيف أو يستبدل، ويمكن تسلسله
get(key)V | undefinedundefined عند غياب المفتاح
has(key)boolean
delete(key)booleantrue إذا حُذف شيء
clear()voidيحذف كل شيء
sizenumberخاصية، وليست دالة
keys()، values()مكررات لـ K وVانشرها في مصفوفة: [...map.keys()]
entries()، for...ofمكرر لـ [K, V]بترتيب الإدراج
forEach((value, key) => ...)voidلاحظ أن القيمة تأتي أولًا

التكرار على Map

تُكرَّر الـ Map بترتيب الإدراج. تعطي for...of على الـ map أزواجًا بالشكل [key, value]، نوعها [K, V].

إسناد قيمة لمفتاح موجود يحدّث القيمة لكنه يُبقي المفتاح في موضعه الأصلي من الترتيب.

المفاتيح من نوع كائن والعدّ

أي قيمة يمكن أن تكون مفتاحًا، بما في ذلك الكائنات والمصفوفات. تُقارن المفاتيح كما تفعل ===: كائنان لهما المحتوى نفسه مفتاحان مختلفان. والـ Map أيضًا هي الطريقة المعتادة لعدّ العناصر أو تجميعها.

لاستخدام محتوى الكائن كمفتاح، اشتق منه مفتاحًا نصيًا أو رقميًا، مثل user.id أو `${x},${y}`.

الفرق بين Map والكائن وRecord

Map<K, V>الكائن / Record<string, V>
أنواع المفاتيحأي نوع، وتُقارن كما في ===string (الأرقام تتحول إلى نصوص)، وsymbol
نوع المفتاح الغائبتعيد get النوع V | undefinedobj[key] نوعه V ما لم يكن noUncheckedIndexedAccess مفعّلًا
الترتيبترتيب الإدراجترتيب الإدراج غالبًا، لكن المفاتيح الشبيهة بالأعداد الصحيحة تأتي أولًا بترتيب تصاعدي
الحجمmap.sizeObject.keys(obj).length
الإضافة والحذف المتكررانمحسّنة لذلكغير محسّن لذلك
JSONليس مباشرة (JSON.stringify(map) يعطي "{}")مباشرة
الصياغة الحرفية والتفكيكلانعم
مفاتيح موروثة عن غير قصدلا يوجد"toString" in {} قيمتها true

قاعدة عملية: Map لمجموعة مفاتيحها بيانات (معرّفات مستخدمين، كلمات، عناصر ذاكرة مؤقتة) وتتغير وقت التشغيل، ونوع كائن أو Record لمجموعة ثابتة من المفاتيح المعروفة ولكل ما يُرسل إلى JSON أو يُقرأ منه. تقارن صفحة القواميس بين index signatures وRecord وMap للبحث بمفاتيح نصية.

تحويل Map إلى كائنات وJSON

عناصر الـ Map ليست خصائص، لذلك لا يراها JSON.stringify. حوّلها عبر Object.fromEntries وObject.entries:

يعيد JSON.parse النوع any، لذلك تصرّح as Record<...> بما يُتوقع أن تكون عليه البيانات. هذا ليس فحصًا وقت التشغيل، فتحقق من JSON غير الموثوق قبل أن تثق بذلك النوع.

تحديد أنواع array.map()

كثير من عمليات البحث عن "typescript map" تقصد دالة المصفوفات التي تحوّل كل عنصر وتعيد مصفوفة جديدة. يُستنتج نوعها من دالة الاستدعاء، لذلك نادرًا ما تحتاج إلى تحديد الأنواع:

تحديد نوع القيمة المُعادة من دالة الاستدعاء ((u): Option => ...) هو أوضح طريقة للتصريح بنوع النتيجة: عندها تصبح أي خاصية مفقودة أو مكتوبة خطأ في الكائن المُعاد خطأ ترجمة عند دالة الاستدعاء.

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

كيف أنشئ Map في TypeScript؟

مرّر نوع المفتاح ونوع القيمة إلى المُنشئ: const ages = new Map<string, number>(). عند تمرير عناصر أولية تُستنتج الأنواع: new Map([["ada", 36]]) نوعه Map<string, number>. أما new Map() دون أنواع ودون عناصر فنوعه Map<any, any>، وهذا يعطّل الفحص، لذلك حدد له الأنواع دائمًا.

لماذا تعيد Map.get القيمة undefined في TypeScript؟

نوع map.get(key) هو V | undefined لأن المفتاح قد لا يكون موجودًا. لا يربط TypeScript بين استدعاء سابق لـ map.has(key) واستدعاء لاحق لـ get، لذلك حتى بعد has عليك التعامل مع undefined: احفظ النتيجة وافحصها، أو استخدم قيمة افتراضية مع ??.

ما الفرق بين Map والكائن في TypeScript؟

الـ Map تقبل مفاتيح من أي نوع (بما فيها الكائنات)، وتحفظ ترتيب الإدراج، ولها الخاصية size، وهي مصممة للإضافة والحذف المتكررين. أما الكائن العادي أو Record<string, V> فمفاتيحه نصوص (ورموز symbol) فقط، ويتحول إلى JSON مباشرة، ويدعم الصياغة الحرفية والتفكيك. استخدم Map للمجموعات الديناميكية ذات المفاتيح، والكائن للأشكال الثابتة وبيانات JSON.

كيف أحوّل Map إلى كائن أو JSON في TypeScript؟

يحوّل Object.fromEntries(map) الـ Map<string, V> إلى كائن عادي، يستطيع JSON.stringify بعدها تحويله إلى نص. استدعاء JSON.stringify(map) على الـ Map نفسها يعطي "{}"، لأن عناصر الـ Map ليست خصائص. والتحويل العكسي هو new Map(Object.entries(obj)).

كيف أحدد نوع دالة الاستدعاء في array.map في TypeScript؟

غالبًا لا تحتاج إلى ذلك: في items.map((item) => item.name) يُستنتج نوع item من المصفوفة، ونوع النتيجة مما تعيده دالة الاستدعاء. لفرض نوع النتيجة مرّره كوسيط نوع، items.map<string>(...)، أو حدد نوع القيمة المُعادة من دالة الاستدعاء.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن