如何在TypeScript中导入没有类型定义的Node模块?

17

当我尝试像这样在TypeScript中导入node.js模块:

import co = require('co');
import co from 'co';

没有提供类型定义,两行代码报告相同的错误:

error TS2307: Cannot find module 'co'.

如何正确导入它?

5个回答

17

窍门是使用纯JavaScript表示:

const co = require('co');

13

你的选择是要么在 TypeScript 的模块系统之外导入它(通过手动调用像 RequireJS 或 Node 这样的模块 API),以便它不尝试验证它,要么添加一个类型定义,以便你可以使用模块系统并使其正确验证。你可以对类型定义进行存根,因此这可以非常轻松。

直接使用 Node (CommonJS)导入:

// Note there's no 'import' statement here.
var loadedModule: any = require('module-name');

// Now use your module however you'd like.

直接使用RequireJS:

define(["module-name"], function (loadedModule: any) {
    // Use loadedModule however you'd like
});

需要注意,在这两种情况下,这可能会与在同一文件中使用真实的TypeScript模块导入混合得很奇怪(特别是在RequireJS方面,你可能会得到两层模块定义,因为TypeScript试图手动管理模块)。我建议只使用这种方法,或者使用真正的类型定义。

存根化类型定义:

获得适当的类型定义是最好的选择,如果有可用的类型定义或者你有时间自己编写,那么你肯定应该这样做。

但如果没有,你可以将整个模块赋予any类型,并将其放入模块系统中,而无需实际对其进行类型标注:

declare module 'module-name' {
    export = <any> {};
}

这样做可以让你导入 module-name 并且让 TypeScript 知道你在说什么。不过你还需要确保使用任何模块系统导入 module-name 在运行时能够成功加载它,否则它会编译但无法真正运行。


1
你能解释一下在存根类型定义文件时应该放在哪里以及使用哪个文件名吗?我不知道什么是"模块系统",我猜TypeScript不知道Node模块的存在,所以我们需要告诉它它们所在的位置。 - arthur.sw
我该如何创建一个满足 import {Provider} from 'react-redux' 导入的存根? - jbandi
如果我将您建议的存根代码放在d.ts文件中,我会收到错误TS2714:导出分配的表达式必须是环境上下文中的标识符或限定名称。 - ahelwer

5

当我使用Tim Perry答案中的"Stubbing type definitions"方法时,我遇到了错误:error TS2497: 模块''module-name''解析为非模块实体,无法使用此结构导入。

解决方案是稍微修改.d.ts文件的存根:

declare module 'module-name' {
  const x: any;
  export = x;
}

然后您可以通过以下方式进行导入:

import * as moduleName from 'module-name';

创建自己的存根文件可降低编写所需声明的难度。

这给了我一个错误 TS2306:文件 'module-name' 不是一个模块。请注意,我正在尝试从本地文件目录导入,而不是从模块导入。 - ahelwer

0

2023年以后的读者都知道,你可以导入它(就像require一样),但必须指定扩展名。例如

import './sockets.js'

即使文件是ts格式,dist编译也会寻找js扩展名并找到模块。
你想要这样做的原因是为了能够在Node文件中使用顶级等待,通过在package.json中指定类型模块,并在tsconfig.json编译器选项属性中指定ESNext模块。

-3

只需以以下方式导入模块:

import 'co';

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接