تايبسكريبت - كيف يمكنني حل الخطأ 'TS2532: قد يكون الكائن غير معرف؟'
أحاول إعادة بناء مثال لتطبيق ويب يستخدم وظائف سحابة Firebase و Firestore. عند نشر وظيفة أحصل على الخطأ التالي:
src/index.ts:45:18 - error TS2532: Object is possibly 'undefined'.
45 const data = change.after.data();
هذه هي الوظيفة:
export const archiveChat = functions.firestore
.document("chats/{chatId}")
.onUpdate(change => {
const data = change.after.data();
const maxLen = 100;
const msgLen = data.messages.length;
const charLen = JSON.stringify(data).length;
const batch = db.batch();
if (charLen >= 10000 || msgLen >= maxLen) {
// Always delete at least 1 message
const deleteCount = msgLen - maxLen <= 0 ? 1 : msgLen - maxLen
data.messages.splice(0, deleteCount);
const ref = db.collection("chats").doc(change.after.id);
batch.set(ref, data, { merge: true });
return batch.commit();
} else {
return null;
}
});
أنا أحاول فقط نشر الدالة لاختبارها. ولقد بحثت بالفعل على الإنترنت عن مشكلات مشابهة، لكن لم أتمكن من العثور على أي منشورات أخرى تتطابق مع مشكلتي.
الإجابة رقم 1
مع إصدار TypeScript 3.7، أصبحت الميزة الاختيارية للتسلسل (المشغّل ?) متاحة رسميًا الآن.
وبالتالي، يمكنك تبسيط تعبيرك إلى ما يلي:
const data = change?.after?.data();
يمكنك قراءة المزيد عنه من ملاحظات إصدار تلك النسخة، التي تغطي ميزات مثيرة أخرى تم إصدارها في تلك النسخة.
قم بتشغيل ما يلي لتثبيت أحدث إصدار مستقر من TypeScript.
npm install typescript
مع ذلك، يمكن استخدام السلسلة الاختيارية جنبًا إلى جنب مع الجمع الصفري لتوفير قيمة بديلة عند التعامل مع القيم null أو undefined
const data = change?.after?.data() ?? someOtherData();
نقاط إضافية:
إذا كنت تستخدم الربط الشرطي الاختياري في جمل if الشرطية، ستظل بحاجة إلى التأكد من أنك تقوم بفحص المطابقة الصحيحة للقيمة/النوع.
سيؤدي ما يلي إلى الفشل في TypeScript الصارم، حيث أنك ربما تقارن قيمة غير معرفة برقم.
if (_?.childs?.length > 0)
بدلاً من ذلك، هذا ما يجب أن تفعله:
if (_?.childs && _.childs.length > 0)
الإجابة رقم 2
تحرير/تحديث:
إذا كنت تستخدم Typescript 3.7 أو أحدث، يمكنك الآن أيضًا القيام بما يلي:
const data = change?.after?.data();
if(!data) {
console.error('No data here!');
return null
}
const maxLen = 100;
const msgLen = data.messages.length;
const charLen = JSON.stringify(data).length;
const batch = db.batch();
if (charLen >= 10000 || msgLen >= maxLen) {
// Always delete at least 1 message
const deleteCount = msgLen - maxLen <= 0 ? 1 : msgLen - maxLen
data.messages.splice(0, deleteCount);
const ref = db.collection("chats").doc(change.after.id);
batch.set(ref, data, { merge: true });
return batch.commit();
} else {
return null;
}
الرد الأصلي
يقول تايبسكريبت أن change أو data قد يكون undefined (اعتمادًا على ما يعيده onUpdate).
لذا يجب عليك تغليفه بفحص للقيمة الفارغة أو غير المعرفة:
if(change && change.after && change.after.data){
const data = change.after.data();
const maxLen = 100;
const msgLen = data.messages.length;
const charLen = JSON.stringify(data).length;
const batch = db.batch();
if (charLen >= 10000 || msgLen >= maxLen) {
// Always delete at least 1 message
const deleteCount = msgLen - maxLen <= 0 ? 1 : msgLen - maxLen
data.messages.splice(0, deleteCount);
const ref = db.collection("chats").doc(change.after.id);
batch.set(ref, data, { merge: true });
return batch.commit();
} else {
return null;
}
}
إذا كنت متأكدًا بنسبة 100٪ من أن object الخاص بك معرف دائمًا، فيمكنك وضع هذا:
const data = change.after!.data();
الإجابة رقم 3
بالنسبة للآخرين الذين يواجهون مشكلة مشابهة لمشكلتي، حيث تعلم أن خاصية معينة للكائن لا يمكن أن تكون فارغة، يمكنك استخدام عامل التأكيد غير الفارغ (!) بعد العنصر المعني. كان هذا هو الكود الخاص بي:
const naciStatus = dataToSend.naci?.statusNACI;
if (typeof naciStatus != "undefined") {
switch (naciStatus) {
case "AP":
dataToSend.naci.certificateStatus = "FALSE";
break;
case "AS":
case "WR":
dataToSend.naci.certificateStatus = "TRUE";
break;
default:
dataToSend.naci.certificateStatus = "";
}
}
وبما أن dataToSend.naci لا يمكن أن يكون غير معرف في عبارة التبديل، يمكن تحديث الكود ليشمل علامات التعجب كما يلي:
const naciStatus = dataToSend.naci?.statusNACI;
if (typeof naciStatus != "undefined") {
switch (naciStatus) {
case "AP":
dataToSend.naci!.certificateStatus = "FALSE";
break;
case "AS":
case "WR":
dataToSend.naci!.certificateStatus = "TRUE";
break;
default:
dataToSend.naci!.certificateStatus = "";
}
}
الإجابة رقم 4
طريقة أخرى يمكنك من خلالها حل مشكلة:
const data = change!.after!.data();
ولكن لاحظ أنه إذا كنت تستخدم eslint قد تحصل على خطأ:
تحذير: لا يُسمح باستخدام التأكيد غير الفارغ. (eslint@typescript-eslint/no-non-null-assertion)
يمكنك تعطيل خطأ كما يلي:
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const data = change!.after!.data();
لكنني لا أنصح باتباع هذا الطريق، من الأفضل تغيير تكوين eslint أو إصلاحه كما هو موضح في الوثائق:
const data = change?.after?.data();
