开启TS strict模式时,解决@tanstack/react-query useQuery返回数据undefined问题
问题:React Query useQuery 返回数据类型无法收窄为非 undefined
我正在开发一个新项目,Typescript 的 strict linting 规则已设为 true。在此规则下,TypeScript 无法确定 @tanstack/react-query 包中 useQuery 钩子返回数据的类型,它可能是实际类型或 undefined。
相关代码
hooks/useFiles.ts
import { useQuery } from '@tanstack/react-query'; import { fileApi } from '@/utils/apiClient'; import { ListFileResponse } from '@types/files'; type useFilesProps = { page?: number; limit?: number; }; export const useFiles = ({ page = 1, limit = 20 }: useFilesProps ) => { return useQuery<ListFileResponse>({ queryKey: ['files'], queryFn: () => fileApi.listFiles({ page, limit }).then((res) => res.data), }); };
views/fileOverview.ts
export const FileOverview = () => { const { data: fileData } = useFiles({ page, limit }); console.log(fileData); // ... };
此处 fileData 的类型为 ListFileResponse | undefined。
即使添加了 isLoading 和 isError 的检查,结果仍然相同:
const { data: fileData, isLoading: isFileLoading, isError: isFileError } = useFiles({ page, limit }); if (isFileLoading) return <p>Loading</p>; if (isFileError) return <p>Error</p> ; console.log(fileData); // 类型仍为 ListFileResponse | undefined
请问需要进行哪些额外检查,才能让 TypeScript linting 确信 fileData 不是 undefined?
解决方案
以下几种方法可以让 TypeScript 确认 fileData 非 undefined:
- 利用
isSuccess状态守卫:React Query 提供的isSuccess状态会在查询成功且数据已加载时为 true,TypeScript 能识别这个状态的类型关联,此时data会自动收窄为非 undefined 类型:
const { data: fileData, isLoading: isFileLoading, isError: isFileError, isSuccess } = useFiles({ page, limit }); if (isFileLoading) return <p>Loading</p>; if (isFileError) return <p>Error</p> ; if (!isSuccess) return null; // 兜底处理其他未覆盖的状态 console.log(fileData); // 此时类型为 ListFileResponse
- 直接检查数据存在性:通过简单的存在性判断(如
fileData或fileData !== undefined),可以让 TypeScript 自动收窄类型:
const { data: fileData, isLoading: isFileLoading, isError: isFileError } = useFiles({ page, limit }); if (isFileLoading) return <p>Loading</p>; if (isFileError) return <p>Error</p> ; if (!fileData) return <p>No data available</p>; console.log(fileData); // 类型收窄为 ListFileResponse
- 配置
initialData:如果查询场景允许设置初始数据,可以在useQuery中指定initialData,这样data的类型会自动排除 undefined:
// 修改 hooks/useFiles.ts export const useFiles = ({ page = 1, limit = 20 }: useFilesProps ) => { return useQuery<ListFileResponse>({ queryKey: ['files'], queryFn: () => fileApi.listFiles({ page, limit }).then((res) => res.data), initialData: [] as ListFileResponse, // 根据实际业务设置合理初始值 }); };
- 非空断言(谨慎使用):如果你能完全确保数据一定存在(比如后端接口绝不会返回空),可以用非空断言操作符
!强制标记数据非 undefined,但这种方式会跳过 TypeScript 的类型检查,仅建议在逻辑绝对安全时使用:
console.log(fileData!); // 强制类型为 ListFileResponse
内容的提问来源于stack exchange,提问作者Thore
相关产品推荐
相关产品推荐

