如何在TypeScript 3.0中使用项目引用?

时间:2018-08-01 11:09:18

标签: typescript module

TypeScript 3.0中有一个名为Project References的新功能。它建议*.ts模块之间更好的交互。不幸的是,尽管这看起来写得非常清楚和直接,但我只能从官方文档中得到所有信息。

任何人都可以帮助我确切地了解它,解决了什么问题,如何做到这一点以及如何从中受益?我有一个结构类似的项目,因此它可能(也可能不会)对此很有帮助。预先谢谢你!


UPD:项目结构大致为:

project/
    lib/
        index.ts # defines the original code
    test/
        index.spec.ts # requires lib/index.ts
    package.json
    tsconfig.json

3 个答案:

答案 0 :(得分:12)

由于该问题受到越来越多的反对,我对此进行了深入研究并设法理解了该功能。希望这个答案会有所帮助。


之前

最初的项目结构与此类似:

/
    lib/
        index.ts # defines the original code
    test/
        index.spec.ts # requires lib/index.ts
    tsconfig.json

这里只有一个 tsconfig.json文件,它表示/(根)文件夹仅包含一个 TypeScript项目,项目本身包括 /lib/test文件夹。

这又意味着编译项目时,输出将包含/test/index.spec.{js|d.ts}个文件。虽然那不是我想要的,所以我将"include"数组添加到/tsconfig.json文件中:

{
    "compilerOptions": {
        // ...
    },
    "include": [
        "./lib"
    ]
}

...以排除除/lib之外的所有内容。

这有所帮助,但不幸的是,TypeScript编译器有时会忽略/test文件夹中的所有文件。


之后

利用项目引用后,project structure具有changed to this

/
    lib/
        index.ts # defines the original code
        tsconfig.json
    test/
        index.spec.ts # requires lib/index.ts
        tsconfig.json
    tsconfig-base.json

现在有两个 tsconfig.json个文件:/lib/tsconfig.json/test/tsconfig.json。这意味着/(根)文件夹现在包含一个非TypeScript项目,其本身具有两个TypeScript“子项目”。

换句话说,我们在项目中添加了模块化。

两个/{lib|test}/tsconfig.json文件都有一些共同的逻辑(假设它们都是"strict": true)。为了指定没有重复,我们将逻辑放在/tsconfig-base.json文件中:

{
    "compilerOptions": {
        "strict": true
    }
}

...并制作两个/{lib|test}/tsconfig.json文件以继承为基础:

{
    "extends": "../tsconfig-base.json"
}

现在,/lib/test基本上是两个具有相同配置的独立TypeScript项目。

最后要做的是指定两者之间的关系。这分两个步骤完成:

  • /lib项目中引用/test项目(因为 tests 取决于 lib ,而不是相反):

    // in /test/tsconfig.json
    {
        "extends": "../tsconfig-base.json",
        "references": [
            { "path": "../lib" }
        ]
    }
    
  • 允许引用/lib项目:

    // in /lib/tsconfig.json
    {
        "extends": "../tsconfig-base.json",
        "compilerOptions": {
            "composite": true
        }
    }
    

此外,现在不需要"include"中的/tsconfig-base.json数组。

通过这些更改,tsc --build lib命令(在根级别)仅编译/lib项目,而不会破坏/test,也不会丢失任何编译错误。

答案 1 :(得分:2)

用于您开发的打字稿库,供其他打字稿应用程序使用。因此,举例来说,如果您制作了lodash之类的实用程序库,但正在与您的依赖应用程序一起积极地开发它,则tsconfig.json`中的references可让您引用源代码,并且在util来源发生变化时(IE:tsc在util ts lib中检测到源代码发生了变化)自动重建您的依赖应用程序

就我而言,我将referencesnpm link和git submodules结合使用,并且效果比ts 2.x天更好。

答案 2 :(得分:-8)

**** UPDATE ****(2018年8月3日)

在信用到期的地方提供信用。

下面的内容是由Microsoft的Daniel Rosenwasser引用的“ Announcing TypeScript 3.0


问题

为库或应用程序执行几个不同的构建步骤是很普遍的。也许您的代码库有一个src和一个test目录。也许您的前端代码位于一个名为client的文件夹中,而Node.js后端代码位于一个名为server的文件夹中,并且每个代码都从一个shared文件夹导入。也许您使用所谓的“ monorepo”,并且有许多项目以非平凡的方式相互依赖。

项目参考

项目参考旨在使这些方案的工作更加轻松。

项目引用允许TypeScript项目依赖于其他TypeScript项目-具体而言,允许tsconfig.json文件引用其他tsconfig.json文件。指定这些依赖性使您更容易将代码拆分为较小的项目,因为它为TypeScript(及其周围的工具)提供了一种理解构建顺序和输出结构的方式。这意味着诸如更快的构建可以逐步运行,并支持跨项目的透明导航,编辑和重构之类的事情。

是什么样子?

作为一个简单的例子,带有项目引用的tsconfig.json如下所示:

// ./src/bar/tsconfig.json
{
    "compilerOptions": {
        // Needed for project references.
        "composite": true,
        "declaration": true,

        // Other options...
        "outDir": "../../lib/bar",
        "strict": true, "module": "esnext", "moduleResolution": "node",
    },
    "references": [
        { "path": "../foo" }
    ]
}

此处需要注意两个新字段:compositereferences

references仅指定其他tsconfig.json文件(或包含它们的文件夹)。当前,每个引用都是一个带有path字段的对象,并让TypeScript知道构建当前项目需要首先构建该引用项目。

composite字段也许同样重要。 composite字段确保启用了某些选项,以便可以为依赖于此项目的任何项目引用和逐步构建此项目。能够智能地进行增量重建很重要,因为构建速度是您可能首先分解项目的原因之一。例如,如果项目front-end依赖于shared,而shared依赖于core,那么我们围绕项目引用的API可用于检测core中的变化,但仅在shared产生的类型(即.d.ts文件)已更改的情况下重建core。这意味着更改core并不会完全迫使我们重建世界。因此,设置composite也会强制设置declaration标志。

TypeScript的构建模式

TypeScript 3.0将提供一组用于项目引用的API,以便其他工具可以提供这种快速的增量行为。 tsc现在带有新的--build标志。

tsc --build(或其昵称,tsc -b)采用一组项目,并构建它们及其依赖项。

控制输出结构

从逻辑上讲,能够将您的输入源映射到其输出,这是项目引用的一个微妙但非常有用的好处。

如果您曾经尝试在应用程序的客户端和服务器之间共享TypeScript代码,则可能会遇到控制输出结构的问题。

例如,如果client/index.tsserver/index.ts都引用shared/index.ts用于以下项目:

src
├── client
│   ├── index.ts
│   └── tsconfig.json
├── server
│   ├── index.ts
│   └── tsconfig.json
└── shared
    └── index.ts

...然后尝试构建clientserver,我们最终会得到...

lib
├── client
│   ├── client
│   │   └── index.js
│   └── shared
│       └── index.js
└── server
    ├── server
    │   └── index.js
    └── shared
        └── index.js

而不是

lib
├── client
│   └── index.js
├── shared
│   └── index.js
└── server
    └── index.js

请注意,我们最终在sharedclient中都复制了server。我们不必要地花了两次时间来构建shared,并在lib/client/clientlib/server/server中引入了不希望的嵌套级别。

理想情况下,TypeScript应该理解这些文件不需要在同一编译中构建,而是可以跳转到.d.ts文件中以获取类型信息。

tsconfig.json创建一个shared并使用项目引用可以做到这一点。它向TypeScript发出信号

  1. shared应该独立构建,并且
  2. ../shared导入时,我们应该在其输出目录中查找.d.ts文件。

这避免了触发双重生成,也避免了意外吸收shared的所有内容。