如何解决错误“ TS2532:对象可能为“未定义”?

Con*_*eer 11 firebase typescript google-cloud-functions google-cloud-firestore

我正在尝试重建使用Firebase Cloud Functions和Firestore的Web应用程序示例。部署功能时,出现以下错误:

src/index.ts:45:18 - error TS2532: Object is possibly 'undefined'.
45     const data = change.after.data();
Run Code Online (Sandbox Code Playgroud)

这是功能:

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;
    }
  });
Run Code Online (Sandbox Code Playgroud)

我只是在尝试部署该功能以对其进行测试。并且已经在网上搜索了类似的问题,但是找不到与我的问题匹配的其他帖子。

wen*_*jun 143

随着 TypeScript 3.7 的发布,可选链(?操作符)现在正式可用。

因此,您可以将表达式简化为以下内容:

const data = change?.after?.data();
Run Code Online (Sandbox Code Playgroud)

您可以从该版本的发行说明中阅读更多相关信息,其中涵盖了该版本发布的其他有趣功能。

运行以下命令以安装最新的稳定版 TypeScript。

npm install typescript
Run Code Online (Sandbox Code Playgroud)

话虽如此,Optional Chaining可以与Nullish Coalescing一起使用,以在处理nullorundefined值时提供后备值

const data = change?.after?.data() ?? someOtherData();
Run Code Online (Sandbox Code Playgroud)

附加点:

如果您在条件if语句中使用可选链,您仍然需要确保您正在执行正确的值/类型相等性检查。

以下将在严格的 TypeScript 中失败,因为您可能正在将未定义的值与数字进行比较。

if (_?.childs?.length > 0) 
Run Code Online (Sandbox Code Playgroud)

相反,这是你应该做的:

if (_?.childs && _.childs.length > 0) 
Run Code Online (Sandbox Code Playgroud)

  • 即使使用可选链接,对象上的数组也存在问题。 (7认同)
  • 即使使用可选链接,我仍然遇到错误 if (_?.childs?.length &gt; 0) (7认同)
  • 有什么办法可以禁用该检查吗?我认为它在打字稿中根本没有用。更新:只需将 `"strictNullChecks": false,` 添加到 tsconfig.json 文件中。 (3认同)
  • 不幸的是,很难在注释中格式化代码,但这里是...我必须提供未定义的检查,因为它会抛出“对象可能未定义”: if (listingData &amp;&amp;listingData.images) { image =listingData?.images[0 ]?.imageUrl; } (2认同)
  • @wentjuin 在许多情况下,它是不可预测的,因此您只需在各处放置许多问号即可删除这些警告,即使它永远不会为空。 (2认同)

dis*_*nte 27

打字稿说的是changedata可能的undefined(取决于onUpdate返回的内容)。

因此,您应该将其包装在null / undefined检查中:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您100%确定object总是定义了您,则可以输入以下内容:

const data = change.after!.data();
Run Code Online (Sandbox Code Playgroud)

  • 使用 `const data = change!.after!.data()` 我收到错误,但使用 `const data = change.after!.data()` 它可以工作。万分感谢。:) (2认同)

Shi*_*raz 11

对于其他面临与我类似问题的人,如果您知道特定对象属性不能为 null,则可以在相关项后使用非空断言运算符 (!)。这是我的代码:

  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 = "";
    }
  }
Run Code Online (Sandbox Code Playgroud)

并且由于dataToSend.naciswitch 语句中不能取消定义,因此可以更新代码以包含感叹号,如下所示:

  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 = "";
    }
  }
Run Code Online (Sandbox Code Playgroud)


小智 8

如何解决问题的另一种方法:

const data = change!.after!.data();
Run Code Online (Sandbox Code Playgroud)

但请注意,如果您使用eslint,您可能会收到错误:

禁止非空断言。(eslint@typescript-eslint/无非空断言)

您可以按如下方式禁用错误:

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const data = change!.after!.data();
Run Code Online (Sandbox Code Playgroud)

但我不建议遵循这种方式,最好更改eslint配置或按照文档中的说明修复它:

const data = change?.after?.data();
Run Code Online (Sandbox Code Playgroud)