使用可选链仍触发TypeError:无法读取undefined的data属性求助
你猜的完全没错!问题就出在索引访问的后面没有跟上可选链操作符。咱们一步步拆解为什么你用了?.还是会报错:
问题根源:可选链的作用范围有限
在你原代码的报错行error.graphQLErrors?.[0].data里:
?.只负责检查error.graphQLErrors是否为null或undefined。如果graphQLErrors确实存在(比如是一个空数组[]),那么[0]会返回undefined。- 这时候你直接访问
.data,就相当于在undefined上读取属性,自然会触发Cannot read property 'data' of undefined的错误——因为可选链的“保护”只到graphQLErrors这一步,后面的索引访问和属性访问并没有被覆盖。
关于variable?.[0]的疑问解答
variable?.[0]里的第一个?.是判断variable本身是否为null/undefined:
- 如果
variable不存在,直接返回undefined,不会执行索引操作; - 如果
variable存在,才会执行[0]索引访问,但索引的结果可能还是undefined(比如数组为空)。
这时候如果要继续访问索引结果的属性,必须在[0]后面再加一个?.,也就是variable?.[0]?.data——第二个?.的作用就是检查索引0对应的结果是否为null/undefined,如果是的话就直接返回undefined,不会继续往下访问.data。
修正后的代码
把所有涉及graphQLErrors?.[0].data的地方,都补上索引后的可选链:
useEffect(() => { let message: string | undefined; const error = createError ?? updateError; if (error) { if ( // @ts-ignore error.graphQLErrors?.[0]?.data?.messages?.[0] // 索引后添加? ) // @ts-ignore message = error.graphQLErrors?.[0]?.data?.messages?.[0]; if (error?.message.includes('same organization as the scenario')) message = 'To create a new scenario, all target areas must be in the same organization as that scenario. You can fix this in the data tab at the top.'; // @ts-ignore if (typeof error?.graphQLErrors?.[0]?.data?.errors?.[1]?.data?.messages?.[0] === 'string') // @ts-ignore message = error?.graphQLErrors?.[0]?.data?.errors?.[1]?.data?.messages?.[0]; if (!message) { message = `Something went wrong with the network request`; console.log(error.message); } addToast(message, 10000); } }, [addToast, createError, updateError]);
额外建议:替代@ts-ignore的更优方案
长期来看,频繁使用@ts-ignore会弱化类型检查的作用,你可以扩展GraphQL Error的类型定义来适配后端返回的结构:
import { GraphQLFormattedError } from 'graphql'; interface GraphQLCustomError extends GraphQLFormattedError { data?: { messages?: string[]; errors?: Array<{ data?: { messages?: string[]; }; }>; }; }
之后把error.graphQLErrors断言为GraphQLCustomError[],就能去掉@ts-ignore,同时获得准确的类型提示。
内容的提问来源于stack exchange,提问作者Diesel
相关产品推荐
相关产品推荐

