如何封装useSWR Hook并实现正确的响应类型推导?
useSWR封装后类型推导失效的原因与解决方案
问题原因分析
你的封装方式存在两个核心问题,导致TypeScript无法正确推导fetcher的响应类型:
- 参数传递方式错误:原
useSWR接收的是分散的rest参数,但你直接将args数组作为单个参数传入useSWR(args),这相当于把整个参数元组当作useSWR的第一个key参数,完全不符合原函数的调用签名。 - 泛型关联丢失:
useSWR本身是泛型函数,依赖<Data, Error>两个泛型参数关联key、fetcher和返回值类型。而你的封装没有显式声明并传递这些泛型,导致Parameters<typeof useSWR>实际上是基于useSWR<any, any>生成的参数类型,丢失了泛型之间的关联关系。
正确的封装方式
要保留原useSWR的类型推导能力,需要显式声明泛型参数,并通过扩展运算符正确传递参数:
import useSWR from 'swr'; // 显式声明与原useSWR对齐的泛型参数 const useMySWR = <Data = any, Error = any>( ...args: Parameters<typeof useSWR<Data, Error>> ) => { // 使用扩展运算符分散传递参数,匹配原函数调用签名 return useSWR<Data, Error>(...args); };
验证类型推导
使用封装后的hook时,TypeScript会自动根据fetcher的返回值推导Data类型:
// 示例fetcher,返回值类型为{ name: string } const fetcher = async (url: string) => { const res = await fetch(url); return res.json() as { name: string }; }; // data的类型会被自动推断为 { name: string } | undefined const { data } = useMySWR('/api/user', fetcher);
深层原理解析
- 泛型参数的显式传递是关键:原
useSWR的参数类型(比如fetcher的类型)依赖<Data, Error>泛型,只有在封装函数上声明相同的泛型,并传递给Parameters<typeof useSWR<Data, Error>>,才能让TypeScript建立起参数与返回值之间的类型关联。 - 扩展运算符的作用:
...args将元组类型的参数分散传递,完全匹配原useSWR的调用签名(useSWR(key, fetcher, options)),而不是把数组当作单个参数传入。
内容的提问来源于stack exchange,提问作者Bright Lee
相关产品推荐
相关产品推荐

