単一リポジトリ内の複数のpackageで共通の型を使い、さらに型をpackage化

# 概要
小規模のサーバーサイド・フロントエンドのように、
マルチパッケージを含む構成のリポジトリにおいて・・・

```
root
├── functions
│   └── package.json    // サーバーサイドの package
└── hosting
    └── package.json    // フロントエンドの package
```

以下を満たすためのメモです。

- functions, hosting から単一の型定義を使う
- `root-types` package として、型を export する
    - ここでexportした型を、外部のプロジェクトからも使えるようにする

## 最終形態
上記の条件を満たすリポジトリの最終形です

```
root
├── package.json  // root-types package
├── types
|   ├── dist      // root-types としての配布物
|   ├── src       // root-types の実装
|   |   ├── index.ts    // root-types で export する名前空間の定義
|   |   ├── modules.ts  // 型をまとめて簡潔に export するためのクッション
|   |   └── impl        // 型の実装
|   |        ├── hoge-types.ts
|   |        └── piyo-types.ts
|   └── tsconfig.json
|
├── functions
│   └── package.json    // サーバーサイドの package
└── hosting
    └── package.json    // フロントエンドの package
```

# root-types package の作成

## package.json
`types/dist` を配布物とします。

```json:package.json
{
  "name": "root-types",
  "main": "types/dist/index.js",
  "files": [ "types/dist" ],
  "scripts": {
    "build": "npx tsc --project types/tsconfig.json",
  },
  "devDependencies": {
    "typescript": "^3.7.4"
  }
}
```

## types/tsconfig.json
`types/dist/` に型定義を出力するように定義します。

```json:types/tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "outDir": "dist",
    "sourceMap": true,
    "strict": true,
    "target": "es2017",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "skipLibCheck": true,
    "declaration": true
  },
  "compileOnSave": true,
  "include": ["src"]
}
```

## types/src/index.ts
`modules.ts` で export しているすべてを、
`Root` という名前でくるんでexportしています

```ts:types/src/index.ts
import * as Root from "./modules";

export { Root };
```

## types/src/modules.ts
`types/src/impl/` 以下の実装をまとめて export するためのクッションです
export 対象のファイルが増えるたび、追記します

```ts:types/src/modules.ts
export * from "./impl/hoge-types";
export * from "./impl/piyo-types";
```

## types/src/impl
export したい型の実装です

```ts:types/src/impl/hoge-types.ts
export interface Hoge {
  str: string;
}
```

```ts:types/src/impl/piyo-types.ts
export enum Piyo {
  ONE = 1,
  TWO = 2,
  THREE = 3,
}
```

## ビルド
`npm run build` を実行すると、 `types/dist/` 以下に型定義 `d.ts` を伴って出力されます

# 内部の package から型を参照
`hosting/` のソースから、通常の package と同様に `root-types` を利用できるようにします
(`functions/` 以下も同様です)

以下のように利用できるようになります。

```ts:hosting/src/index.ts
import { Root } from 'root-types';

const hoge: Root.Hoge = {str: "hello"};
console.log(hoge, Root.Piyo.ONE);
// {str: "hello"} 1
```

## [方法1] npm link
`hosting/` 以下で `npm link ../` を実行すると、
`hosting/node_modules/` 以下に `root-types` のシンボリックリンクが生成されます

### postinstall に link を記述
このままでは毎回 `npm link ../` を実行しなくてはなりません。

そこで、 `hosting/package.json` に以下の script を追記し、
npm install 後に自動的に実行されるようにします

```json:hosting/package.json
  "scripts": {
    "postinstall": "npm link ../",
  }
```

## [方法2] npm install <localdir>
こっちのほうが楽かもしれません。
`./hosting` で `npm install ../` を実行するだけです
↓

```json:hosting/package.json
"dependencies": {
    "root-types": "file:..",
}
```


# 外部の package から利用する
今回作成した `root-types` package はほかの private プロジェクトで参照するのみで、
npm に publish したりはしません。
外部のプロジェクトで、 `root` リポジトリを直接参照して `root-types` をinstallできました。

`npm install git+ssh://git@gitlab.com:YOU/root.git --save`
↓

```json:package.json
"dependencies": {
  "root-types": "git+ssh://git@gitlab.com:YOU/root.git",
}
```

参考
[nodejsで自作別リポジトリ(gitlab/github)をモジュール化して利用するには？](http://kei0425tan.hatenablog.com/entry/2017/05/11/170245)

# まとめ
マルチパッケージのリポジトリで型を共有したり、
型をexportして他のリポジトリで使ったりする機会が増えてきたので書きました。

同一リポジトリ・マルチパッケージでサクッと楽して開発できるだけで、
キレイスッキリな構成ではない気がするので、
大きく育てるプロジェクトではもっと最適なソリューションがないか検討したいですね。