How to use project references in TypeScript 3.0?

后端 未结 2 1950
甜味超标
甜味超标 2020-12-23 01:59

There is this new feature in TypeScript 3.0 called Project References. It suggests better interaction of *.ts modules between themselves. Unfortunately, this is

相关标签:
2条回答
  • 2020-12-23 02:20

    TL;DR:

    The feature allows to define parts of the project as separate TypeScript modules. Among other things, this allows configuring those modules differently, building them separately etc.


    Before

    Initially, the project structure, when simplified, is similar to this:

    /
        src/
            entity.ts # exports an entity
        test/
            entity.spec.ts # imports an entity
        tsconfig.json
    

    An entity is defined in src/entity.ts module, and then used in test/entity.spec.ts file.

    Notice that there is only one tsconfig.json file here, sitting in the root folder. This basically says that this folder contains one big solid TypeScript project. This project includes a couple of files, organized in folders; some of those files are used for testing other ones.

    This structure however imposes a problem: the process of compiling the project (namely, tsc) also compiles the test files, thus creating dist/test/entity.spec.{js|d.ts} files in the output. This should not happen, therefore the tsconfig.json file is slightly altered to include only those files/folders that are intended for outside usage:

    {
        "compilerOptions": {
            // compiler options
        },
        "include": [
            "./src"
        ]
    }
    

    This solves the problem, but in my case it also led to all files in /test folder being occasionally ignored by the TypeScript compiler during the development process. Also, this exclusive approach might not fit for everybody.


    After

    After utilizing the feature, the project structure has changed to this:

    /
        src/
            entity.ts # exports an entity
            tsconfig.json
        test/
            entity.spec.ts # imports an entity
            tsconfig.json
        tsconfig-base.json
    

    Let's go through the changes:

    1. Renaming /tsconfig.json to /tsconfig-base.json is a pretty major thing by itself: the root folder is not a TypeScript project anymore, since tsc requires tsconfig.json file to be present.
    2. On the other hand, adding src/tsconfig.json and test/tsconfig.json files turns both src and test into two separate TypeScript projects, independent from each other.

    The contents of /{src|test}/tsconfig.json files are similar, since no changes in configuration were expected, i.e., the "strictness", the output folder, as well as other such parameters, should be preserved. In order to make them similar without copy-pasting anything, all the configurations are put in an arbitrary file, accessible from both places; in this case, the tsconfig-base.json in the root folder was selected for that:

    // the contents of /tsconfig-base.json
    {
        "compilerOptions": {
            // compiler options, common to both projects
        }
    }
    

    This file is being "inherited" then by /{src|test}/tsconfig.json files, with addition of any other options if needed:

    // the contents of /{src|test}/tsconfig.json
    {
        "extends": "../tsconfig-base.json",
        "compilerOptions": {
            // additional compiler options, specific to a project
        }
    }
    

    Notice how this pattern is similar to defining an abstract class with incomplete implementation, and then extending it by two separate "concrete" classes.

    Now, /src and /test folders basically hold two separate TypeScript projects with similar configuration. The last thing to do is to specify relation between the two. Since test depends on src, the test have to somehow "know" about src. This is done in two pretty obvious steps:

    • allow src to be "referenced" from the outside by declaring it as "composite":

      // in /src/tsconfig.json
      {
          "extends": "../tsconfig-base.json",
          "compilerOptions": {
              // compiler options
              "composite": true
          }
      }
      
    • reference src from test:

      // in /test/tsconfig.json
      {
          "extends": "../tsconfig-base.json",
          "references": [
              { "path": "../src" }
          ]
      }
      

    The "include" array in /tsconfig-base.json is not needed now, since the code exclusion is done by "drawing new borders".

    UPDATE: the following section seems to be outdated since TypeScript 3.7

    Now, the test project requires *.d.ts files for src project to be present. This means that before running tests, the src should already be built, separately. This is done by using the new mode of tsc, triggered by --build option:

    tsc --build src
    

    This command builds src project and puts the output in the specified output folder (in this case, /dist), without neither breaking test, nor losing any compile errors.

    0 讨论(0)
  • 2020-12-23 02:27

    it's for typescript libraries you develop, that are used by other typescript application. So for example, if you make some util library like lodash but are actively developing it along side your dependent application, the references in ``tsconfig.json``` lets you reference the source code, and have your dependent application be rebuilt automatically when the util source changes (IE: tsc detects source code changes in the util ts lib)

    In my case specifically, I use the references in conjunction with npm link and git submodules and it's working out a lot better than in the ts 2.x days.

    0 讨论(0)
提交回复
热议问题