自定义SWR Hook返回类型与预期类型不匹配问题排查
解决SWR泛型Hook生成器的类型推断问题
我在使用SWR库开发一个基于泛型的Block Hook生成器,输入mapParamsToKey和request方法来生成对应的SWR Hook,但生成的Hook返回的SWRResponse类型不符合预期——data的类型被推断为any,而不是request方法返回的Promise泛型类型。
问题代码示例
import useSWR from 'swr'; type Params = { id: number; }; type BlogPost = { id: number; title: string; }; const mapParamsToKey = (params: Params) => ['blog-post', params.id]; const request = (params: Params): Promise<BlogPost> => { const data = { id: params.id, title: `Blog Post ${params.id}` }; return Promise.resolve(data); }; // 手动编写的Hook能正确推断出SWRResponse<BlogPost, any, any> const useBlogPost = (params: Params) => useSWR(mapParamsToKey(params), () => request(params)); // 泛型Hook生成器 function createBlockHook<P, T = any>(config: { mapParamsToKey: (params: P) => Array<string | number>; request: (params: P) => Promise<T>; }) { return (params: P) => useSWR(config.mapParamsToKey(params), () => config.request(params)); } // 生成的Hook返回SWRResponse<any, any, any>,不符合预期 const useBlogPost2 = createBlockHook<Params>({ mapParamsToKey, request, });
解决方案
问题根源在于泛型参数T的默认值设置:当你只显式指定<Params>时,T会使用默认值any,而不会自动从request方法的返回值中推断类型。可以通过两种方式修复:
方式1:移除T的默认值,让TypeScript自动推断所有泛型参数
修改createBlockHook的泛型定义,去掉T的默认值any,调用时无需手动指定泛型参数,TypeScript会自动从传入的config中推断P和T:
function createBlockHook<P, T>(config: { mapParamsToKey: (params: P) => Array<string | number>; request: (params: P) => Promise<T>; }) { return (params: P) => useSWR(config.mapParamsToKey(params), () => config.request(params)); } // 自动推断P=Params,T=BlogPost,返回SWRResponse<BlogPost, any, any> const useBlogPost2 = createBlockHook({ mapParamsToKey, request, });
方式2:显式指定所有泛型参数
如果需要手动指定P的类型,同时也要显式指定T的类型,确保类型匹配:
const useBlogPost2 = createBlockHook<Params, BlogPost>({ mapParamsToKey, request, });
修正后的预期使用场景
import client from './my-api-client'; type CommentParams = { id: number; } const useComment = createBlockHook({ mapParamsToKey: (params) => ['comment', params.id], request: client.getComment, // (params: CommentParams) => Promise<Comment> }); function Comment(props: { id: number }) { const swr = useComment(props); if (swr.data) { // swr.data现在会正确提示Comment类型 return ( <div>{swr.data.content}</div> ) } return <div>...</div>; }
内容的提问来源于stack exchange,提问作者feat.com
相关产品推荐
相关产品推荐

