Jest29+Node.js18+ESM环境下正确Mock全局Fetch并解决TS类型问题
解决Jest 29 + Node.js 18 ESM环境下全局fetch Mock的TypeScript类型问题
Node.js 18开始内置了fetch API,但TypeScript的全局类型定义默认没把fetch加到globalThis/global上,再加上Jest 29的ESM环境类型适配问题,直接mock全局fetch会触发类型错误。下面给两种不用//@ts-ignore的正确解法:
解法一:扩展全局类型声明
在项目根目录新建types/global.d.ts(或types/jest.d.ts),手动给全局对象添加fetch的mock类型:
declare global { namespace NodeJS { interface Global { fetch: jest.Mock; } } interface Window { fetch: jest.Mock; } } // 必须加这行,让TypeScript识别为模块文件 export {};
接着修改tsconfig.json,确保TypeScript能读取这个类型文件:
{ "compilerOptions": { "typeRoots": ["./node_modules/@types", "./types"], // 其他编译配置... }, "include": ["src/**/*", "types/**/*"] }
之后再mock全局fetch就不会有类型错误了:
globalThis.fetch = jest.fn(() => Promise.resolve({ json: () => Promise.resolve({ data: 'test' }) }) );
解法二:用jest.spyOn结合类型断言(更推荐)
不需要修改全局类型,直接用jest.spyOn来捕获并mock fetch,通过类型断言让TypeScript识别正确类型:
// 把globalThis.fetch断言为jest的SpyInstance const mockFetch = jest.spyOn(globalThis, 'fetch') as jest.SpyInstance<typeof fetch>; // mock返回值,用as Response匹配类型 mockFetch.mockResolvedValue({ json: jest.fn().mockResolvedValue({ data: 'test' }) } as Response);
这种方式更灵活,适合单测中针对性mock,还能方便地在测试结束后恢复原始fetch:
afterEach(() => { mockFetch.mockRestore(); });
附上适配ESM的package.json配置
{ "name": "your-project", "type": "module", "scripts": { "test": "jest" }, "devDependencies": { "@types/jest": "^29.5.0", "jest": "^29.5.0", "ts-jest": "^29.1.0", "typescript": "^5.0.0" }, "jest": { "preset": "ts-jest/presets/default-esm", "extensionsToTreatAsEsm": [".ts"], "moduleNameMapper": { "^(\\.{1,2}/.*)\\.js$": "$1" }, "globals": { "ts-jest": { "useESM": true } } } }
"type": "module":开启项目的ESM模式ts-jest预设用default-esm:适配TypeScript的ESM编译moduleNameMapper:解决ESM下导入路径不带.js后缀的问题
内容的提问来源于stack exchange,提问作者Jan Beneš
相关产品推荐
相关产品推荐

