value instanceof SomeClass فحص JavaScript يعمل وقت التشغيل: يكون true عندما يوجد SomeClass.prototype في سلسلة النماذج الأولية للكائن، أي أن الكائن أُنشئ بـ new SomeClass (أو بصنف فرعي). وتضيّق TypeScript نوع value إلى SomeClass داخل الفحص.
استخدم instanceof للكائنات المنشأة من أصناف، وtypeof للأنواع البدائية. هنا نحتاج إلى الاثنين: يفصل instanceof قيمة Date، ثم يقسم typeof ما تبقى.
تضييق أصنافك الخاصة
يضيّق instanceof إلى الصنف في الفرع true ويحذفه في الفرع false، فيمكن معالجة union من الأصناف عضوًا بعد عضو.
نسخة الصنف الفرعي تجتاز أيضًا الفحص للصنف الأب: إذا كان Square extends Rect، فإن new Square(2) instanceof Rect يساوي true. افحص الصنف الأكثر تحديدًا أولًا عندما تختلف الفروع.
أصناف Error الفرعية في catch
أكثر استخدامات instanceof شيوعًا يكون في catch. تحت strict تكون القيمة الملتقطة unknown (أي شيء يمكن رميه)، وinstanceof هو طريقة العودة إلى خطأ له نوع.
الناتج:
404: /missing.txt
TypeError: path must be absolute
يعمل class X extends Error مع instanceof على كل هدف تدعمه TypeScript 7 (ES2015 وما بعده). والنصيحة القديمة باستدعاء Object.setPrototypeOf(this, X.prototype) في المُنشئ كانت تخص الكود المترجم إلى ES5، وهو هدف أزالته TypeScript 7.
instanceof لا يعمل مع الواجهات أو الأنواع
الواجهات وtype aliases موجودة للمترجم فقط. بعد الترجمة لا توجد قيمة User للمقارنة بها، لذلك ترفض TypeScript الفحص:
يبلّغ المترجم index.ts(8,24): error TS2693: 'User' only refers to a type, but is being used as a value here. هناك حلان. افحص الشكل بنفسك بـ type guard، أي دالة تعيد value is User:
أو، إذا كان كودك ينشئ هذه الكائنات، فاجعل User صنفًا وأنشئها بـ new؛ عندها يعمل instanceof. وتغطي صفحة type guards الـ predicates ودوال التأكيد بالتفصيل.
النوع الصحيح ليس النسخة الصحيحة
تقارن TypeScript الأنواع بحسب البنية: الكائن الحرفي الذي له أعضاء الصنف نفسها يمكن إسناده إلى نوع الصنف. أما instanceof فلا ينظر إلى البنية. إنه يمشي في سلسلة النماذج الأولية، والكائن الذي لم يُنشأ قط بـ new يفشل فيه حتى عندما يقبله المترجم كذلك النوع.
السطر الأخير مهم. structuredClone وJSON.parse(JSON.stringify(...)) والرسائل بين workers كلها تعيد كائنات عادية بلا النموذج الأولي للصنف، رغم أن نوعها الثابت قد يظل يقول Point. عندما تعبر نسخ الأصناف حدودًا كهذه، أعد بناءها (new Point(copy.x, copy.y)) قبل الاعتماد على instanceof أو على الدوال.
instanceof والأنواع البدائية
الأنواع البدائية (string وnumber وboolean...) ليست كائنات وليست لها سلسلة نماذج أولية، لذلك "hi" instanceof String يساوي false. وتعلّم TypeScript الخطأ عندما تستطيع: مع قيمة نوعها string في الطرف الأول يكون instanceof هو الخطأ TS2358، The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter. استخدم typeof للأنواع البدائية.
| القيمة | فحص instanceof | الناتج |
|---|---|---|
new Date() | instanceof Date | true |
[1, 2] | instanceof Array | true (لكن فضّل Array.isArray) |
new TypeError("x") | instanceof Error | true (صنف فرعي) |
{ x: 1, y: 2 } | instanceof Point | false (لم يُنشأ قط) |
Object.create(null) | instanceof Object | false (بلا نموذج أولي) |
"hi" | instanceof String | false (قيمة بدائية) |
القيم من نطاقات تنفيذ أخرى
يقارن instanceof مع كائن مُنشئ واحد محدد. الكود الذي يعمل في نطاق تنفيذ آخر (realm)، مثل iframe أو سياق vm في Node، له Array وError وDate خاصة به، لذلك تفشل مصفوفة أُنشئت هناك في instanceof Array هنا. ويحدث الشيء نفسه عندما تنتهي نسختان من حزمة npm واحدة في node_modules: لكل نسخة صنفها الخاص، والنسخة من إحداهما تفشل في instanceof مقابل الأخرى. للمصفوفات يعمل Array.isArray عبر النطاقات. ولأنواعك الخاصة، يتجنب فحص خاصية (type guard، أو حقل kind) المشكلة كليًا.
الأسئلة الشائعة
كيف أتحقق من أن كائنًا نسخة من صنف في TypeScript؟
استخدم value instanceof ClassName. إنه فحص وقت التشغيل (JavaScript عادية)، وتضيّق TypeScript نوع value إلى ClassName داخل if. يعمل مع الأصناف المدمجة مثل Date وMap وError ومع أصنافك الخاصة.
هل يمكنني استخدام instanceof مع interface في TypeScript؟
لا. تُمحى الواجهات وtype aliases عندما تترجم TypeScript إلى JavaScript، فلا يوجد ما يُفحص مقابله وقت التشغيل. x instanceof User مع واجهة User هو الخطأ TS2693، "'User' only refers to a type, but is being used as a value here." افحص الخصائص بدالة type guard بدلًا من ذلك، أو اجعل User صنفًا إذا كنت تنشئ الكائنات بنفسك.
لماذا يعيد instanceof القيمة false لكائن من النوع الصحيح؟
أنواع TypeScript بنيوية: الكائن الحرفي { x: 1, y: 2 } يمكن إسناده إلى نوع الصنف Point إذا كانت له الأعضاء نفسها. لكن instanceof يفحص سلسلة النماذج الأولية (prototype chain)، والكائن الحرفي لم يُنشأ قط بـ new Point، فيكون الناتج false. ويحدث الشيء نفسه لنسخ الأصناف التي مرت عبر JSON أو structuredClone أو قناة رسائل، فتعود ككائنات عادية.
هل يعمل instanceof مع أصناف Error المخصصة في TypeScript؟
نعم، مع أي هدف حديث. class NotFound extends Error {} ثم err instanceof NotFound يساوي true. المشكلة القديمة التي كان يعيد فيها false كانت تخص فقط الناتج المترجم إلى ES5، ولم تعد TypeScript 7 تدعم الهدف ES5.
لماذا "hello" instanceof String يساوي false؟
النص الحرفي قيمة بدائية لا كائن، فلا توجد سلسلة نماذج أولية لفحصها. لا يكون instanceof String صحيحًا إلا مع الكائنات المغلِّفة المنشأة بـ new String(). وترفض TypeScript استخدام instanceof على قيمة نوعها string (TS2358)؛ استخدم typeof value === "string" للأنواع البدائية.