安装多个 typescript 类型定义,声明相同的全局变量

Posted

技术标签:

【中文标题】安装多个 typescript 类型定义,声明相同的全局变量【英文标题】:Install multiple typescript type definitions declaring the same global variable 【发布时间】:2018-08-19 17:31:53 【问题描述】:

我正在使用 typescript、node 和 electron 构建一个应用程序。

我在应用程序中使用 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 '$'.

问题是两个包都声明了一个全局 $ 变量。您也可以在“全局值”下的 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编写的代码示例,它们一起使用:这在打字稿中不可行吗?

【问题讨论】:

【参考方案1】:

好久不见,终于找到解决办法了!

您需要定义两个单独的 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 和类型

默认情况下,所有可见的“@types”包都包含在你的 编译。任何封闭文件夹的 node_modules/@types 中的包 被认为是可见的;具体来说,这意味着包内 ./node_modules/@types/, ../node_modules/@types/, ../../node_modules/@types/,等等。

如果指定了 typeRoots,则只有 typeRoots 下的包会被 包括在内。

...

指定“类型”:[] 以禁用自动包含 @types 包。

请记住,自动收录仅在您满足以下条件时才重要 使用具有全局声明的文件(与声明为的文件相反 模块)。 例如,如果您使用 import "foo" 语句, TypeScript 可能仍会查看 node_modules 和 node_modules/@types 文件夹来查找 foo 包。

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

【讨论】:

以上是关于安装多个 typescript 类型定义,声明相同的全局变量的主要内容,如果未能解决你的问题,请参考以下文章

【笔记】使用Vite搭建Vue3(TypeScript版本)项目

如何在 Vue Router v4 中为自定义元字段声明 TypeScript 类型接口?

感受typescript定义变量和数据类型的神奇魔力

在 Typescript 中声明一个委托类型

关于typescript之定义变量和数据类型那点事

TypeScript:如何在编译时声明固定大小的数组以进行类型检查