typescript - Hur kan jag lösa felet 'TS2532: Objektet kan vara 'undefined'?
Jag försöker återskapa ett webbapplikationsexempel som använder Firebase Cloud Functions och Firestore. När jag distribuerar en funktion får jag följande fel:
src/index.ts:45:18 - error TS2532: Object is possibly 'undefined'.
45 const data = change.after.data();
Det här är funktionen:
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;
}
});
Jag försöker bara distribuera funktionen för att testa den. Och jag har redan sökt på nätet efter liknande problem, men kunde inte hitta några andra inlägg som matchar mitt problem.
Svar #1
Med lanseringen av TypeScript 3.7 är optional chaining (operatorn ?) nu officiellt tillgänglig.
Som sådan kan du förenkla ditt uttryck till följande:
const data = change?.after?.data();
Du kan läsa mer om det i den versionens versionsanteckningar, som täcker andra intressanta funktioner som släpptes i den versionen.
Kör följande för att installera den senaste stabila versionen av TypeScript.
npm install typescript
Det sagt kan Optional Chaining användas tillsammans med Nullish Coalescing för att tillhandahålla ett reservvärde när man hanterar null eller undefined-värden
const data = change?.after?.data() ?? someOtherData();
Ytterligare punkter:
Om du använder valfri kedjning i de villkorliga if-satserna måste du fortfarande säkerställa att du gör korrekt värde-/typjämförelse.
Följande kommer att misslyckas i strikt TypeScript, eftersom du möjligen jämför ett odefinierat värde med ett tal.
if (_?.childs?.length > 0)
Istället är detta vad du borde göra:
if (_?.childs && _.childs.length > 0)
Svar #2
Redigera/Uppdatera:
Om du använder Typescript 3.7 eller nyare kan du nu också göra:
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;
}
Originalt svar
Typescript säger att change eller data möjligen är undefined (beroende på vad onUpdate returnerar).
Så du bör omsluta det i en null/undefined-kontroll:
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;
}
}
Om du är 100% säker på att ditt object alltid är definierat, kan du skriva detta:
const data = change.after!.data();
Svar #3
För andra som står inför ett liknande problem som mitt, där du vet att en viss objekts egenskap inte kan vara null, kan du använda icke-null-assertionsoperatorn (!) efter det aktuella objektet. Detta var min kod:
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 = "";
}
}
Och eftersom dataToSend.naci inte kan vara undefined i switch-satsen, kan koden uppdateras för att inkludera utropstecken på följande sätt:
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 = "";
}
}
Svar #4
Ett sätt till hur du kan lösa ett problem:
const data = change!.after!.data();
Men observera att om du använder eslint kan du få ett fel:
Otillåten icke-null-assertion. (eslint@typescript-eslint/no-non-null-assertion)
Du kan inaktivera ett fel på följande sätt:
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const data = change!.after!.data();
Men jag rekommenderar inte att följa detta sätt, det är bättre att ändra eslint-konfigurationen eller åtgärda det som anges i dokumentationen:
const data = change?.after?.data();
