使用 typescript 在节点项目中导入 node-fetch

Sow*_*wam 19 javascript node.js typescript fetch-api

如何将node-fetch包导入到我使用typescript. 我尝试了很多方法......现在我正在:

const fetch = (...args) =>
    import("node-fetch").then(({ default: fetch }) => fetch(...args));
Run Code Online (Sandbox Code Playgroud)

但我有两个错误:

Cannot redeclare block-scoped variable 'fetch'.
Run Code Online (Sandbox Code Playgroud)

A spread argument must either have a tuple type or be passed to a rest parameter.
Run Code Online (Sandbox Code Playgroud)

当我更改const fetch =为任何其他名称时,例如const fetchIt =它修复了第一个错误,但是......我真的必须更改它吗?如何node-fetch以正常方式导入包,我可以使用fetch()方法?在 React 中我只是做

import fetch from 'node-fetch';
Run Code Online (Sandbox Code Playgroud)

一切都很好......为什么在node项目中如此困难?

qqi*_*ihq 18

如果您与 global 发生冲突fetch,这表明您已启用该DOMtsconfig.json,例如:

{
  "compilerOptions": {
    "lib": ["es2021", "dom"]
  }
}
Run Code Online (Sandbox Code Playgroud)

我建议删除这个。对于 NodeJS 项目,请查看tsconfig.json答案,了解根据 NodeJS 版本的建议设置。

之后,您将能够按照fetch您在问题中所写的方式导入并将其分配给名为 的变量fetch,而不会发生名称冲突:

import fetch from 'node-fetch';
Run Code Online (Sandbox Code Playgroud)

替代解决方案:如果您需要使用以浏览器焦点构建的第三方库并且需要全局获取,请查看该isomorphic-fetch模块,该模块添加fetch为全局函数。

您需要导入一次,以便fetch全局可用:

import 'isomorphic-fetch';
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您的编译器选项tsconfig.json应该包含该dom库。

更新2022-02-04

较新的 NodeJS 版本fetch现在提供了原生 API,因此以后不再需要上面的内容。请参阅此处此处了解更多信息。


Chr*_*ris 6

更新:

我下面的原帖全部属实。不过,我已经能够让它工作,而无需切换到 ESM 模块。这是我的代码中的工作内容(基于以下帖子中的第三个代码片段: https://github.com/node-fetch/node-fetch/issues/1279#issuecomment-915063354

// eslint-disable-next-line no-new-func
const importDynamic = new Function('modulePath', 'return import(modulePath)');

const fetch = async (...args:any[]) => {
  const module = await importDynamic('node-fetch');
  return module.default(...args);
};
Run Code Online (Sandbox Code Playgroud)

原帖:

Cannot redeclare block-scoped variable 'fetch'错误是因为您声明了一个const fetch变量,然后在该行后面重用了名称“ fetch”作为回调函数的对象解构参数。then()

因此,将行更改为如下内容可以清除该错误:

const fetch = (...args) => import("node-fetch").then(module => module.default(...args));
Run Code Online (Sandbox Code Playgroud)

至于另一个错误 ( A spread argument must either have a tuple type or be passed to a rest parameter.),解决此问题的一种可能方法是实际导入调用的正确参数类型fetch(),然后根据需要替换上面的代码片段,如下所示:

import { RequestInfo, RequestInit } from 'node-fetch';
const fetch = (url:RequestInfo, init?:RequestInit) => import('node-fetch').then(module => module.default(url, init));
Run Code Online (Sandbox Code Playgroud)

不幸的是,虽然这似乎满足 TypeScript 编译器的要求,但我在自己的代码中发现运行时仍然无法工作(抛出 ),ERR_REQUIRE_ESM因为我的 TypeScript 配置当前使用 CommonJS 模块而不是 ESM 格式。

请参阅https://github.com/node-fetch/node-fetch/issues?q=ERR_REQUIRE_ESM了解与此问题相关的 node-fetch 包中的几个未决问题。

本质上,node-fetch 维护者建议我们这些使用 TypeScript 的人需要转换为 ESM 模块,远离 CommonJS(请参阅https://github.com/node-fetch/node-fetch/issues/1397#issuecomment-978092116和后续评论)。


Tam*_*yce 5

降级或安装 v2。npm install node-fetch@2 && npm install --save-dev @types/node-fetch@2.x

当节点不支持 ESM 3.x 时,它还有什么意义呢?至少对于tsc来说是这样。也许 ts-node 支持它。但 tsc 应该与 ts-node 兼容。

import { default as fetch, Headers } from 'node-fetch';
Run Code Online (Sandbox Code Playgroud)

tsconfig

{
    "$schema": "https://json.schemastore.org/tsconfig",
    "display": "Node 12",
    "compilerOptions": {
      "lib": ["es2019"],
      "module": "commonjs",
      "target": "es2019",
      "strict": true,
      "esModuleInterop": true,
      "skipLibCheck": true,
      "forceConsistentCasingInFileNames": true,
      "moduleResolution": "node"
    },
    "include": [
        "**/*.ts"
    ]
  }
Run Code Online (Sandbox Code Playgroud)

注意:节点14,将tsconfig从上面的es2019更新为es2020并显示节点14

此外,Node 17+ fetch 是内置的。因此,当节点支持 ESM 时,您可能不需要节点获取。