使用TypeScript模拟global.fetch时遇类型不兼容错误求助
解决Jest模拟global.fetch时的TS2322类型错误
问题原因
TypeScript对fetch的返回类型有严格校验,fetch实际返回的是Promise<Response>,而你之前的模拟仅实现了json方法,缺少Response接口定义的headers、ok、status等十余项属性,导致类型不匹配报错。
解决方案
方法1:完整模拟Response对象属性
创建完全符合Response类型的mock对象,填充所有要求的属性:
type Data = { id: number; name: string; }; global.fetch = jest.fn(() => Promise.resolve({ // 核心业务相关属性 ok: true, json: () => Promise.resolve([{ id: 1, name: 'Test Item' }] as Data[]), // 其他必填属性填充默认值或mock headers: new Headers(), status: 200, statusText: 'OK', type: 'basic', url: '', redirected: false, body: null, bodyUsed: false, clone: jest.fn(), formData: jest.fn(), blob: jest.fn(), text: jest.fn(), arrayBuffer: jest.fn(), }) ) as jest.Mock;
方法2:用类型断言简化模拟
如果不想填充所有属性,可通过类型断言跳过TypeScript的严格校验(适合快速测试场景):
type Data = { id: number; name: string; }; global.fetch = jest.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve([{ id: 1, name: 'Test Item' }] as Data[]), // 仅保留核心属性,其余用类型断言忽略 } as unknown as Response) ) as jest.Mock;
方法3:封装复用的mockFetch工具
如果多个测试都需要模拟fetch,可封装工具函数提高复用性:
type Data = { id: number; name: string; }; const mockFetch = (data: Data[], ok = true) => { return jest.fn(() => Promise.resolve({ ok, json: () => Promise.resolve(data), headers: new Headers(), status: ok ? 200 : 404, statusText: ok ? 'OK' : 'Not Found', type: 'basic', url: '', redirected: false, body: null, bodyUsed: false, clone: jest.fn(), formData: jest.fn(), blob: jest.fn(), text: jest.fn(), arrayBuffer: jest.fn(), }) ); }; // 测试中调用 global.fetch = mockFetch([{ id: 1, name: 'Test Item' }]);
测试示例(结合组件)
假设你的列表组件代码如下:
// ListComponent.tsx import { useEffect, useState } from 'react'; import type Data from './types'; export default function ListComponent() { const [data, setData] = useState<Data[]>([]); const [loading, setLoading] = useState(true); useEffect(() => { const fetchData = async () => { try { const res = await fetch('/api/data'); if (!res.ok) throw new Error('Fetch failed'); const result = await res.json(); setData(result); } catch (err) { console.error(err); } finally { setLoading(false); } }; fetchData(); }, []); if (loading) return <div>Loading...</div>; return ( <ul> {data.map(item => ( <li key={item.id}>{item.name}</li> ))} </ul> ); }
对应的测试代码(使用方法2的类型断言):
// ListComponent.test.tsx import { render, screen, waitFor } from '@testing-library/react'; import ListComponent from './ListComponent'; import type Data from './types'; describe('ListComponent', () => { beforeEach(() => { jest.clearAllMocks(); global.fetch = jest.fn(() => Promise.resolve({ ok: true, json: () => Promise.resolve([{ id: 1, name: 'Test Item' }] as Data[]), } as unknown as Response) ) as jest.Mock; }); it('renders list after fetching data', async () => { render(<ListComponent />); // 验证加载状态 expect(screen.getByText('Loading...')).toBeInTheDocument(); // 等待数据渲染完成 await waitFor(() => { expect(screen.getByText('Test Item')).toBeInTheDocument(); }); // 验证fetch调用 expect(fetch).toHaveBeenCalledTimes(1); expect(fetch).toHaveBeenCalledWith('/api/data'); }); });
内容的提问来源于stack exchange,提问作者user1189352
相关产品推荐
相关产品推荐

