React Query中useQuery赋值后回调内类型收窄失效问题
React Query中useQuery数据赋值后的类型收窄问题
在React Query里,useQuery返回的data类型是T | undefined,直接对data做类型收窄时TypeScript能正常识别,但把data赋值给另一个变量后,在回调函数里对该变量的类型收窄会失效——比如在map这类回调里,变量仍被判定为T | undefined。
代码示例
const { data } = useQuery<number[]>("test", () => [1, 2, 3, 4]); let data2 = data; // 此处对data2做过滤、排序等处理... const fun0 = () => { if (!data) return; // 无类型错误 [1, 2, 3].map((one) => data[0]); }; const fun = () => { if (!data2) return; // 此处正常,data2被识别为number[] const foo = data2[0]; // 类型错误:data2仍被判定为number[] | undefined [1, 2, 3].map((one) => data2[0]); };
问题原因
TypeScript对const和let的类型跟踪逻辑不同:
useQuery返回的data是const声明的,TypeScript能确定它的引用不会被篡改,所以在if (!data)判断后,后续所有对data的引用都会被认定为非undefined,包括回调内部。- 而
let data2 = data是可变变量,TypeScript无法保证在if (!data2)判断结束后、回调执行前,data2不会被重新赋值为undefined,因此在回调里不会认可之前的类型收窄结果。
解决方案
方案1:改用const声明变量
如果后续不需要修改data2,直接用const替代let,TypeScript就能正常跟踪其类型:
const data2 = data; // 替换let为const
方案2:收窄后存入常量再使用
如果必须用let(比如需要修改data2),可以在类型收窄后把值存入一个const变量,后续回调里使用这个常量:
const fun = () => { if (!data2) return; const safeData = data2; // safeData被推断为number[] [1, 2, 3].map((one) => safeData[0]); // 无类型错误 };
方案3:类型断言(不推荐)
如果能确保data2在回调执行时一定非undefined,可以用类型断言强制指定类型,但这种方式会跳过TypeScript的类型检查,存在风险:
[1, 2, 3].map((one) => (data2 as number[])[0]);
内容的提问来源于stack exchange,提问作者Xun Yang
相关产品推荐
相关产品推荐

