Edited at

TypeScript 3.0 の Project reference(プロジェクト参照) やってみた

More than 1 year has passed since last update.

TypeScript 3.0 がリリースされました。

追加機能のひとつ、Project references は、ちょうど仕事で「どうするのがいいの?」と迷ってたところだったので、さっそくやってみました。

話としてはよくある、 複数のプロジェクトから参照される "共通プロジェクト" の在り方 です。


Project Reference 適用以前

Project Reference 適用前(つまり現状)は、次のような構成になっていました(説明簡略化のため、client -> shared のみを書いてますが serverside からも shared を参照しています)。

root

├── client
│ ├── tsconfig.json
│ └── src
│ └── main.ts
└── shared
└── src
└── calc.ts

shared の calc.ts

export function calcAdd(x: number, y: number): number {

return x + y;
}

client の main.ts

import { calcAdd } from '../../shared/src/calc';

console.log(calcAdd(1, 2)); // = 3

client の tsconfig.json

{

"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true
}
}

shared/ 配下 は ただのファイル置き場 で、client から相対パスで calc.ts を参照しているに過ぎません。

これを tsc -b client/tsconfig.json した結果は次のようになります。

root

├── dist
│ ├── client
│ │ └── src
│ │ └── main.js
│ └── shared
│ └── src
│ └── calc.js
├── client
│ └─-
└── shared
└─-

これはイケてないと思いつつ開発してきましたが、これを Project reference に変えてみます。


Project reference 適用後

ではプロジェクト参照を使ってみます。TypeScript Version 3.0.1 で試しています。

まず、 shared/ をプロジェクト化するために tsc --inittsconfig.json を作り、内容を次のようにします。

shared の tsconfig.json

{

"compilerOptions": {
// tsc --init で既定で設定されてた項目
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,

// あとから追加した項目
"outDir": "../dist/shared",
"rootDir": "./src",
"composite": true,
"declaration": true,
}
}

"composite": true がプロジェクト参照のために必要な項目で、"declaration": true は、型定義ファイルを出力するために必要です(よね?)。outDirrootDir は出力される .js ファイルの場所を調整するために設定しました。

次に client 側の tsconfig.json を修正します。

client の tsconfig.json

{

"compilerOptions": {
// tsc --init で既定で設定されてた項目
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,

// あとから追加した項目
"outDir": "../dist/client",
"rootDir": "./src",

// さらに追加した相対パス地獄を防ぐための項目
"baseUrl": "./",
"paths": {
"shared/*": [
"../dist/shared/*"
]
}
},
// あとから追加した項目
"references": [
{ "path": "../shared" }
]
}

こちらには、 "references" を追加し、shared への参照を設定します。これがプロジェクト参照のメインですね。

baseUrlpaths は、 "relative path hell" を回避するための設定です。

を見てやってみました。

最後に、client の main.tsimport 文を書き換えます。

client の main.ts

import { calcAdd } from 'shared/calc';

console.log(calcAdd(1, 2)); // = 3

import は、shared プロジェクトのビルド結果である ./dist/shared を参照するようにしますが、 先に baseUrlpathsshared/*../dist/shared/* をマッピングさせているので、ここでは from 'shared/calc' だけで済みます。

ではビルドしてみましょう。

tsc -b client/tsconfig.json

を実行します。ポイントは、shared もプロジェクトなのにそれは含めていない、ということです。

ビルド結果を含むディレクトリ全体は次のようになります。

root

├── client
│ ├── tsconfig.json
│ └── src
│ └── main.ts
├── shared
│ ├── tsconfig.json
│ └── src
│ └── calc.ts
└── dist
├── client
│ └── main.js
└── shared
├── calc.js
└── calc.d.ts

なんだかそれっぽくなった気がします。

tsc -b client/tsconfig.json としたのに、プロジェクト参照に設定されている shared 側も(先に)ビルドされて dist/shared に出力されています。

client の tsconfig.json には "rootDir": "./src" を設定したので、好き勝手に別の親ディレクトリにある .ts ファイルを参照することができなくなり、秩序が守られる気がします。

冒頭の説明には、もっとたくさんのオプションについて説明がありますが、とりあえず以上です。