You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

构建Prismic头部巨型菜单时遇ContentRelationship类型错误求解决

Prismic巨型菜单构建中的ContentRelationshipField类型错误解决方法

问题场景

构建网站头部巨型菜单时,使用Prismic客户端查询header文档数据,在格式化子菜单数据时触发TypeScript类型错误:

Property 'data' does not exist on type 'ContentRelationshipField<"header_submenu">'.
  Property 'data' does not exist on type 'EmptyLinkField<"Document">'.

原因分析

Prismic的ContentRelationshipField是联合类型,包含两种状态:

  • 已关联文档:拥有data属性,存储关联的文档数据
  • 空关联(EmptyLinkField):没有data属性,表示未关联任何文档

TypeScript会严格校验这种不确定性,直接访问item.submenu.data会触发错误,因为无法保证submenu一定是已填充状态。

解决方法

通过空值检查明确submenu的状态,让TypeScript确认data属性存在后再访问,同时处理空关联的边界情况。

方案1:使用Prismic官方工具函数

导入Prismic的isFilled工具函数,快速判断字段是否已填充:

import { isFilled } from '@prismicio/client';

const formatHeaderData = (data: Simplify<HeaderDocumentData>) => {
  const { menu, logo } = data;

  const formattedMenu = menu.length
    ? menu.map((item) => {
        // 检查子菜单是否为已填充的关联字段
        const submenuData = isFilled.contentRelationship(item.submenu) ? item.submenu.data : null;
        
        return {
          label: item.label,
          is_link: item.is_link,
          link: item.link,
          submenu: submenuData
            ? {
                cta_image: submenuData.cta_image,
                menu: submenuData.menu.map((subMenuItem) => {
                  // 检查子菜单项是否为已填充的关联字段
                  const itemData = isFilled.contentRelationship(subMenuItem.item) ? subMenuItem.item.data : null;
                  return itemData
                    ? {
                        menu_label: itemData.menu_label,
                        menu: itemData.menu,
                      }
                    : {
                        menu_label: '',
                        menu: [],
                      };
                }),
              }
            : {
                cta_image: null,
                menu: [],
              },
        };
      })
    : [];
  
  return {
    logo,
    menu: formattedMenu,
  };
};

方案2:手动判断字段状态

如果不想依赖工具函数,可以手动判断字段的linkType和data是否存在:

const formatHeaderData = (data: Simplify<HeaderDocumentData>) => {
  const { menu, logo } = data;

  const formattedMenu = menu.length
    ? menu.map((item) => {
        // 手动判断子菜单是否已填充
        const isSubmenuValid = item.submenu?.linkType === 'Document' && item.submenu.data;
        const submenuData = isSubmenuValid ? item.submenu.data : null;
        
        return {
          label: item.label,
          is_link: item.is_link,
          link: item.link,
          submenu: submenuData
            ? {
                cta_image: submenuData.cta_image,
                menu: submenuData.menu.map((subMenuItem) => {
                  // 手动判断子菜单项是否已填充
                  const isItemValid = subMenuItem.item?.linkType === 'Document' && subMenuItem.item.data;
                  const itemData = isItemValid ? subMenuItem.item.data : null;
                  return itemData
                    ? {
                        menu_label: itemData.menu_label,
                        menu: itemData.menu,
                      }
                    : {
                        menu_label: '',
                        menu: [],
                      };
                }),
              }
            : {
                cta_image: null,
                menu: [],
              },
        };
      })
    : [];
  
  return {
    logo,
    menu: formattedMenu,
  };
};

效果说明

修改后,TypeScript会识别到我们已经处理了空关联的情况,不再触发类型错误;同时代码也能兼容子菜单未填充的场景,避免运行时出现Cannot read property 'data' of undefined的报错。

内容的提问来源于stack exchange,提问作者Nick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 21:07:05