Cloud Run functions × TypeScript 開発をしよう！【開発環境：TypeScript環境 ─ tsconfig.jsonの設定】

# はじめに
この章では以下の内容について説明します。
- typscript実行環境の作り方
- `tsconfig.json`の記述方法

---

Cloud Run functionsでのTypeScript環境の作り方は人によってバラバラで「コレ！」という方法が今のところ見つかっていない感じがあります。
しかし僕的には本記事（と次の記事）で紹介する方法が一番シンプルでスマートだと思います。

# 想定ディレクトリ
```bash
├── package.json
├── package-lock.json
└── src
    └── index.ts
```
前回と異なる点は、ソースファイルを格納する`src`ディレクトリを作成し、そこにソースコードをぶち込むようにしています。

# TypeScript実行環境の構築
## typescriptパッケージのインストール
```bash
npm install --save-dev typescript
```

これによって`tsc`コマンドが使えるようになり、`index.ts` → `index.js` にトランスパイル（簡単にいうと変換）できるようになります。

## `tsconfig.json`の作成
実は `tsconfig.json` は別に作らなくてもtypescirpt使えます。がだと言って作らないでおくと色々面倒なので作っておきましょう。
`tsc --init` で `tsconfig.json`が作成されます。

...が、使いづらいので**使いません**。試しに実行してみましょう。

```bash:試しにtsconfig.jsonを作成するコマンドを実行
npx tsc --init
```

```bash:結果
Created a new tsconfig.json with:                                                                                       
  target: es2016
  module: commonjs
  strict: true
  esModuleInterop: true
  skipLibCheck: true
  forceConsistentCasingInFileNames: true


You can learn more at https://aka.ms/tsconfig
```

```js:出力されるtsconfig.json
{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig to read more about this file */

    /* Projects */
    // "incremental": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
    // "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */
    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */
    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
    // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */

    /* Language and Environment */
    "target": "es2016",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
    // "lib": [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
    // "jsx": "preserve",                                /* Specify what JSX code is generated. */
    // "experimentalDecorators": true,                   /* Enable experimental support for legacy experimental decorators. */
    // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
    
    // ...
```

...ほとんどコメントアウト...😅
見にくいし、~~全く~~あんまり使えません。

2024年現在、Cloud Run functions用にスクラッチから作るなら以下のようになると思います。

```js:Cloud Run functions用のシンプルなtsconfig.json
{
  "compilerOptions": {
    "target": "es2022",
    "module": "node16",
    "moduleResolution": "node16",
    "baseUrl": "./src",
    "paths": {
      "@/*": ["./*"]
    },
    "rootDirs": ["./src"],
    "outDir": "./dist",
    "sourceMap": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
  },
  "include": ["src/**/*"],
  "exclude": ["dist", "node_modules"]
}
```
特に説明した方がよさそうな項目について説明していきます。
### target
TS → JSへのトランスパイル時にどのバージョンのJavaScriptで出力するかを記載します。
`es2023`以下に設定するのが適切そうですが、`es2022` にしておきます。理由は後述します。

https://node.green/#ES2023

### module
トランスパイスしたJSを動かす環境が期待しているモジュール形式です。

Node.jsの設定値で正しいのは `node16` か `nodenext` です。 `commonjs` と `esnext` を設定するのは誤りのようです。


https://www.typescriptlang.org/docs/handbook/modules/theory.html#the-module-output-format

> Node.js’s rules for module format detection and interoperability make it incorrect to specify module as esnext or commonjs for projects that run in Node.js, even if all files emitted by tsc are ESM or CJS, respectively.

`nodenext`ではバージョンが動的に変わってしまうため、`node16`に設定します。

そして `node16` に設定すると暗示的に `target` は `es2022` に、`moduleResolution` は `node16` に変わるみたいです。`target` を `es2023` にしなかったのはこの理由からです。
設定する意味ないぢゃん！

https://www.typescriptlang.org/docs/handbook/modules/reference.html#implied-and-enforced-options

Moduleの話は公式リファレンスでも詳しく説明されていますので、参考ください。

https://www.typescriptlang.org/docs/handbook/modules/introduction.html

### baseUrl
どこを起点にモジュール解決するかの設定。
例えば、以下のようなディレクトリ構成で`baseUrl`を`./src`とした場合、
```bash:例
project_root
    └─ src
        ├── services
        │   ├── product.ts
        │   └── order.ts
        ├── lib
        │   └── time.ts
        └── index.ts
```

`src/service/product.ts` から `src/lib/time.ts` を**相対パスを使わないで**参照する場合、以下の記述でファイル参照ができます。

```js:src/service/product.ts
import time from 'lib/time';
```

もちろん、相対パスは通常通り使えます。

```js:src/service/product.ts
import time from '../lib/time';
```

ただ、以下はNGです。

```src/service/product.ts
import time from 'order'; // ./src/order.ts が参照される
```

### rootDirs
どのディレクトリ階層以降をコンパイル対象にするかの設定。
`./src` より前のディレクトリ階層を指定しようとするとエラーになる。

```bash:例
project_root
    ├── src
    │   ├── services
    │   │   ├── product.ts
    │   │   └── order.ts
    │   ├── lib
    │   │   └── time.ts
    │   └── index.ts
    └── sample.ts
```

以下の呼び出しはNGになります。

```js:src/service/product.ts
import sample from '../../sample'; // NG
```

### paths
モジュール解決の際にエイリアスを設定できるオプション。
`baseUrl`を指定するとその位置を基準にとしてエイリアスが設定される。

```js:paths
// ...
    "paths": {
      "@/*": ["./*"] // @/xxx で src/xxx を指定したのと同じ
    }, 
```

例えば以下のようにできる。

```js:src/service/product.ts
// import time from '../lib/time' がスッキリする
import time from '@/lib/time';
```

ただし注意ですが、tscによるトランスパイル後のJSファイルを実行しようとするとエラーになります。
```bash:あれ？
src/index.ts:2:24 - error TS2307: Cannot find module '@/xxx' or its corresponding type declarations.
```
トランスパイル後のJSファイルを見てみるとわかるのですが、エイリアスがそのまま出力されており、パス解決ができない状態になっています。
```js:./dist/index.js
var sample_1 = require("@/test/sample"); // エイリアスがそのまま出力されてしまっている
```

大事なことなのですが、**トランスパイルしただけではimportのパス解決はできません。** 別途ビルドツールを使ってモジュール解決できるよう変換する必要があります（違っていたら教えてください）。
次章以降でこの解決方法を紹介していきます。


# おわりに
こうして構築した環境を利用して、次の記事ではTypeScript上でCloud Run functions関数を実行する方法を紹介していきます。

# 参考文献

https://www.typescriptlang.org/tsconfig/

https://qiita.com/ryokkkke/items/390647a7c26933940470

https://zenn.dev/chida/articles/bdbcd59c90e2e1