You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 07:25:19