简体   繁体   English

使用 typescript 在节点项目中导入节点获取

[英]Importing node-fetch in node project with typescript

How can I import node-fetch package to my node project where I use typescript .如何将node-fetch package 导入我使用typescript的节点项目。 I tried it in many ways... right now I am on:我尝试了很多方法……现在我在:

const fetch = (...args) =>
    import("node-fetch").then(({ default: fetch }) => fetch(...args));

But I have 2 errors:但是我有两个错误:

Cannot redeclare block-scoped variable 'fetch'.

and

A spread argument must either have a tuple type or be passed to a rest parameter.

When I change const fetch = to any other name like const fetchIt = it fixes first error but... do I really have to change that?当我将const fetch =更改为const fetchIt =之类的任何其他名称时,它修复了第一个错误但是......我真的必须改变它吗? How can I import node-fetch package in normal way where I can use fetch() method?如何在可以使用fetch()方法的情况下以正常方式导入node-fetch package? In React I just make在 React 中我只是做

import fetch from 'node-fetch';

and everything works fine... why is that so hard in node projects?一切正常......为什么在node项目中如此困难?

If you have conflicts with a global fetch , this suggests that you have the DOM lib in your tsconfig.json enabled, eg:如果您与全局fetch发生冲突,这表明您在tsconfig.json中启用了DOM库,例如:

{
  "compilerOptions": {
    "lib": ["es2021", "dom"]
  }
}

I would suggest removing this.我建议删除它。 For a NodeJS project, have a look at this answer for the suggested tsconfig.json settings depending on the NodeJS version.对于 NodeJS 项目,根据 NodeJS 版本查看建议的tsconfig.json设置的答案

After this, you will be able to import fetch as you wrote in your question and assign it to a variable named fetch , without conflicting names:在此之后,您将能够按照您在问题中所写的方式导入fetch并将其分配给名为fetch的变量,而不会出现名称冲突:

import fetch from 'node-fetch';

Alternative solution: If you need to work with 3rd party libs which are built with a browser focus and require a global fetch, have a look at the isomorphic-fetch module, which adds fetch as global function.替代解决方案:如果您需要使用以浏览器为重点并需要全局提取的第 3 方库,请查看isomorphic-fetch模块,该模块将fetch添加为全局 function。

You will need to import it once so that fetch is available globally:您将需要导入一次,以便fetch在全球范围内可用:

import 'isomorphic-fetch';

In this case, the compiler options of your tsconfig.json should contain the dom lib.在这种情况下,您的tsconfig.json的编译器选项应该包含dom库。

Update 2022-02-04 2022-02-04 更新

Newer NodeJS versions ship a native fetch API now, so above will no longer be necessary going forward.较新的 NodeJS 版本现在提供本机fetch API,因此以后不再需要上述内容。 See here and here for more information.有关更多信息,请参见此处此处

Update:更新:

My original post below is all true.我下面的原始帖子都是真的。 I have been able to get it to work, however, without having to switch to ESM modules.然而,我已经能够让它工作,而无需切换到 ESM 模块。 Here is what's working in my code (based on the third code snippet in the following post: https://github.com/node-fetch/node-fetch/issues/1279#issuecomment-915063354 )这是我的代码中的工作内容(基于以下帖子中的第三个代码片段: 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);
};

Original Post:原帖:

The Cannot redeclare block-scoped variable 'fetch' error is because you're declaring a const fetch variable, and then reusing the name " fetch " as the object-destructured parameter to the then() callback later in the line. Cannot redeclare block-scoped variable 'fetch'错误是因为您要声明一个const fetch变量,然后在该行后面的then()回调中重用名称“ fetch ”作为对象解构参数。

So, changing the line to read as follows clears up that error:因此,将行更改为如下所示可以清除该错误:

const fetch = (...args) => import("node-fetch").then(module => module.default(...args));

As for the other error ( A spread argument must either have a tuple type or be passed to a rest parameter. ), one possible way to solve this would be to actually import the correct argument types for the fetch() call, then substitute in the above code snippet as appropriate, like this:至于另一个错误( 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));

Unfortunately, while that seems to satisfy the TypeScript compiler, I'm finding in my own code that the runtime still doesn't work (throws an ERR_REQUIRE_ESM ) because my TypeScript config is currently using CommonJS modules rather than an ESM format.不幸的是,虽然这似乎满足 TypeScript 编译器,但我在自己的代码中发现运行时仍然不起作用(抛出ERR_REQUIRE_ESM ),因为我的 TypeScript 配置当前使用的是 CommonJS 模块而不是 ESM 格式。

See https://github.com/node-fetch/node-fetch/issues?q=ERR_REQUIRE_ESM for several open issues in the node-fetch package related to this problem.有关与此问题相关的节点获取 package 中的几个未解决问题,请参阅https://github.com/node-fetch/node-fetch/issues?q=ERR_REQUIRE_ESM

Essentially, the node-fetch maintainers are suggesting those of us using TypeScript need to convert to ESM modules, away from CommonJS (see https://github.com/node-fetch/node-fetch/issues/1397#issuecomment-978092116 and subsequent comments).本质上,node-fetch 维护者建议我们这些使用 TypeScript 的人需要转换为 ESM 模块,远离 CommonJS(参见https://github.com/node-fetch/node-fetch/issues/1397#issuecomment-97809216和后续评论)。

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

What is the point of ESM 3.x when node doesn't support it?当节点不支持 ESM 3.x 时,ESM 3.x 有什么意义? At least for tsc.至少对于 tsc。 Maybe ts-node supports it.也许 ts-node 支持它。 But tsc should be compatible with ts-node.但 tsc 应该与 ts-node 兼容。

import { default as fetch, Headers } from 'node-fetch';

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"
    ]
  }

Note: Node 14, update tsconfig to es2020 from es2019 above & display Node 14注意:节点 14,将 tsconfig 从上面的 es2019 更新为 es2020 & 显示节点 14

I suggest using cross-fetch , it is almost the same but works everywhere, it helped me because I was not able to run node-fetch in TypeScript我建议使用cross-fetch ,它几乎相同,但在任何地方都可以使用,它对我有帮助,因为我无法在 TypeScript 中运行 node-fetch

This setup worked for me:这个设置对我有用:

package.json package.json

{
  "main": "index.ts",
  "scripts": {
    "start": "ts-node --esm ./src/index.ts"
  },
  "type": "module",
  "dependencies": {
    "@types/node": "^18.11.18",
    "@types/node-fetch": "^2.6.2",
    "node-fetch": "^3.3.0",
    "nodemon": "^2.0.20",
    "ts-node": "^10.9.1",
    "typescript": "^4.9.5"
  }
}

tsconfig.json tsconfig.json

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "lib": ["ES2022", "DOM"],
    "module": "ES2022",
    "moduleResolution": "node",
    "target": "ES2022",
    "esModuleInterop": true,
  }
}

index.ts索引.ts

import fetch, { Headers } from 'node-fetch';
// do something

I was using ts-node, so notice you need to apply the --esm compatibility:我使用的是 ts-node,所以请注意您需要应用--esm兼容性:

ts-node --esm./src/index.ts

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM