安装声明相同全局变量的多个打字稿类型定义

Install multiple typescript type definitions declaring the same global variable

我正在使用打字稿、节点和电子构建应用程序。

我在应用程序中使用 jquery 并且我已经安装了 @types/jquery 包以提供智能提示。

接下来我使用 mocha 和 spectron 创建了一个测试。 Spectron 利用 webdriverio 并通过一些属性公开其 API。我需要使用这些属性,所以我安装了@types/webdriverio 以获得智能提示。

现在,每当我 运行 使用 tsc 工具编译项目时,我都会收到以下错误:

node_modules/@types/jquery/index.d.ts(36,15): error TS2451: Cannot redeclare block-scoped variable '$'.
node_modules/@types/webdriverio/index.d.ts(1898,18): error TS2451: Cannot redeclare block-scoped variable '$'.
node_modules/@types/webdriverio/index.d.ts(1899,18): error TS2451: Cannot redeclare block-scoped variable '$'.

问题是两个包都声明了一个全局 $ 变量。您也可以在 "Global values":

下的 npm 页面中验证它

https://www.npmjs.com/package/@types/jquery

https://www.npmjs.com/package/@types/webdriverio

我不明白为什么 tsc 试图将它们编译在一起,因为我没有在同一个 .ts 文件中使用 jquery 和 webdriverio?

此外,即使我注释掉了测试,所以我没有在任何地方引用 webdriverio,当我 运行 tsc 时,我也会得到同样的错误。可能 tsc 正在一起编译 node_modules/@types 中的所有源代码。事实上,如果我删除 node_modules/@types/webdriverio 文件夹并再次执行 运行 tsc,我不会得到任何错误(当然,只要我保留测试代码注释)。

这是我的 tsconfig.json,它位于项目的根目录中:

{
    "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "sourceMap": false,
        "inlineSourceMap": true,
        "inlineSources": true,
        "declaration": false,
        "outDir": "dist"
    },
    "include": [
        "src/**/*"
    ]
}

我所有的源代码都在 src 目录中。测试在 src/test.

是否可以进行任何配置以在编译时将 webdriverio 和 jquery 类型分开?另外,我看到一些用 js 写的代码示例,它们一起使用:这在 typescript 中不可行吗?

好久没找到解决办法了!

您需要定义两个单独的 tsconfig:一个用于主项目,一个用于测试。

tsconfig.project.json

{
    "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "sourceMap": false,
        "inlineSourceMap": true,
        "inlineSources": true,
        "watch": false,
        "declaration": false,
        "outDir": "dist",
        "typeRoots": ["./typings"],
    },
    "include": [
        "src/**/*"
    ],
    "exclude": [
        "src/test/*"
    ]
}

tsconfig.test.json

{
    "compilerOptions": {
        "target": "ES6",
        "module": "commonjs",
        "sourceMap": false,
        "inlineSourceMap": true,
        "inlineSources": true,
        "watch": false,
        "declaration": false,
        "outDir": "dist",
        "typeRoots": ["./typings"],
    },
    "include": [
        "src/test/*"
    ]
}

然后,在 package.json 文件中针对您刚刚定义的两个 tsconfig 定义两个不同的脚本 运行 tsc:

{
...
  "scripts": {
    "test": "tsc -p tsconfig.test.json && mocha --exit dist/test",
    "tsc": "tsc -p tsconfig.project.json",
    ...
  },
...
}

关键点是 typeRoots 配置,它覆盖了 typescript 编译器的默认行为。默认行为是加载在任何 @types 文件夹下定义的每个包(因此包含 node_modules 文件夹中安装的每个 @types)。 通过覆盖此配置,node_modules 中的@types 仅在引用时包含在内。或者,您可以将 typeRoots 配置替换为

"types": []

来自https://www.typescriptlang.org/docs/handbook/tsconfig-json.html

@types, typeRoots and types

By default all visible “@types” packages are included in your compilation. Packages in node_modules/@types of any enclosing folder are considered visible; specifically, that means packages within ./node_modules/@types/, ../node_modules/@types/, ../../node_modules/@types/, and so on.

If typeRoots is specified, only packages under typeRoots will be included.

...

Specify "types": [] to disable automatic inclusion of @types packages.

Keep in mind that automatic inclusion is only important if you’re using files with global declarations (as opposed to files declared as modules). If you use an import "foo" statement, for instance, TypeScript may still look through node_modules & node_modules/@types folders to find the foo package.

另外一个重要的点是分离配置文件。这样您就可以在编译主项目时排除测试文件,反之亦然。这一点很重要,因为主项目包括 jquery,而测试文件包括 webdriverio。将它们一起编译你会得到问题中描述的相同错误。