🍂

TypeScript のコンパイルと Node.js 実行の流れ

2024/11/17に公開

はじめに

新規プロジェクトで Node.js のベース実装をしているのですが...
tsconfig.json の設定がよくわからない、そもそもどう動いているのかから怪しいと思い、TypeScript にわかだなと反省したので調べました。
TypeScript のコンパイルと Node.js 実行の流れについてや tsconfig.json について、実際に手を動かしてコンパイルをしながら学んだことをまとめた内容になっています!

TypeScript のコンパイルと Node.js 実行の流れ

そもそも Node.js と TypeScript とは

Node.js とは Javascript の実行環境で、サーバーサイドで JavaScript を実行できるようにしたものです。TypeScript とは JavaScript を拡張したプログラミング言語であり、静的型付け(型チェック)によってコードの安全性を向上させます。

TypeScript は開発用のコードであり、そのままでは Node.js で実行できないため、JavaScriptに変換(コンパイル)する必要があります。

TypeScript で開発してから Node.js で実行までのフロー

以下のような流れです。

  1. TypeScript で開発する。
  2. TypeScriptのコンパイラーであるtscでコンパイル (TypeScript → JavaScript)
    • TypeScript の型チェック。
    • エラーがない場合は JavaScript ファイルを生成。
  3. 生成された JavaScript を Node.js で実行。
実際に TypeScript をコンパイルしてNode.js で実行してみます。

① 新規フォルダを作成し、以下コマンドでpackage.jsonを作成

$ npm init

② TypeScript のコンパイラをインストール

$ npm install typescript

これにより、tscというコマンドが使用できるようになります。

③ hello.tsを作成

hello.ts
const message: string = "Hello! TypeScript!";
console.log(message);

④ TypeScriptをコンパイル

$ tsc hello.ts

コンパイルが成功するとhello.jsファイルが作成されます。

⑤ JavaScriptをNode.jsで実行

$ node hello.js

ターミナルにHello! TypeScript!と表示されます。

tsconfig.json とは

tsconfig.json とは TypeScript から JavaScript にコンパイルするための設定ファイルです。
プロジェクト内の TypeScript ファイルをどのようにJavaScript に変換するかを指定することができます。

tsconfig.json が作成されます。

$ tsc --init

よく使用するオプションを紹介します。※オプションを紹介してくれている記事がたくさんあるのでここではあまり詳しく書かないです。

include

コンパイルする対象ファイルを記述します。
ワイルドカード (* ) や再帰パターン (**/*) を使うことができます。
ファイル名は tsconfig.json ファイルを含んでいるディレクトリからの相対パスとして解決されます。

https://www.typescriptlang.org/ja/tsconfig/#include

exclude

include で指定したファイルから特別に除外するファイルを記述します。

extends

他の tsconfig.json 設定ファイルを継承 するためのプロパティです。
特にモノレポリポジトリで共通設定をまとめた ベースの tsconfig.json を作成し、それを各プロジェクトで継承する場合に使われます。

compilerOptions

TypeScript のコンパイル動作を制御します。一部だけ紹介します。

オプション 説明
target トランスパイル後の JavaScript のバージョンを指定。 "ESNext", "ES2023"
module モジュールの形式を指定(Node.js 用なら "CommonJS", ESM 用なら "ESNext")。 "CommonJS","ESNext"
moduleResolution モジュール解決方法を指定。 "Node","NodeNext"
strict 厳密な型チェックを有効化。複数の設定をまとめてオンにする便利なオプション。 true
outDir 生成される JavaScript の出力先ディレクトリを指定。 "dist"
rootDir ソースファイルのルートディレクトリを指定。 "src"

compilerOptionsには型チェックに関する設定やモジュール解決に関する設定、型定義ファイルやJavaScriptファイルをどのように出力するかの設定などの様々な設定があります。これらの設定を使うことで、プロジェクトごとに統一したルールを適用し、型安全性やモジュール管理、出力コードのフォーマットを細かく調整できます。

参考
https://typescriptbook.jp/reference/tsconfig/option-list
https://qiita.com/ryokkkke/items/390647a7c26933940470

実際に tsconfig.json に従って TypeScript をコンパイルしてみます。

① 以下コマンドで tsconfig.json を作成します。

$ tsc --init

このようなディレクトリ構成です。

.
├── node_modules
├── package-lock.json
├── package.json
├── src
│   └── greet.ts
└── tsconfig.json

② tsconfig.json の中身を記述します。

tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext", // トランスパイル後の JavaScript のバージョンを指定
    "module": "NodeNext", // モジュール形式を指定
    "moduleResolution": "NodeNext", // モジュール解決方法を指定
    "outDir": "dist", // 出力先ディレクトリを指定
    "rootDir": "src" // ソースファイルのルートディレクトリを指定
  },
  "include": ["src/**/*"], // コンパイル対象ファイルを指定
  "exclude": ["node_modules", "dist"] // 除外するディレクトリを指定
}

③ TypeScript をコンパイルします。

$ tsc

"outDir": "dist"の設定に従ってdistファイル配下にJavaScriptファイルが出力されました。

続いてtargetを古いもの(ES5)に変更して TypeScript をコンパイルしてみます。

① tsconfig.json の中身を記述します。

{
  "compilerOptions": {
-   "target": "ESNext", // トランスパイル後の JavaScript のバージョンを指定
+   "target": "ES5", // トランスパイル後の JavaScript のバージョンを指定 (ES5に変更)
    "module": "ESNext", // モジュール形式を指定
    "moduleResolution": "NodeNext", // モジュール解決方法を指定
    "outDir": "dist", // 出力先ディレクトリを指定
    "rootDir": "src" // ソースファイルのルートディレクトリを指定
  },
  "include": ["src/**/*"], // コンパイル対象ファイルを指定
  "exclude": ["node_modules", "dist"] // 除外するディレクトリを指定
}

② TypeScript をコンパイルします。

$ tsc

ES5 は古い JavaScript バージョンで、アロー関数や let / const、テンプレートリテラルなどを含まない仕様です。そのため、出力されたgreet.jsは以下のように変換されて出力されます。

dist/greet.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var greet = function (name) {
    return "Hello, ".concat(name, "!");
};
var name = "TypeScript";
console.log(greet(name));
  • constvarに変換
  • アロー関数 (=>) が通常の関数 (function) に変換
  • ${name}などのテンプレートリテラルが"Hello, " + name + "!"のように文字列結合に変換

開発時は TypeScript を直接実行するツールを用いる

TypeScript ファイルをtscでコンパイルしてから生成された JavaScript ファイルをnodeで実行するのは、毎回手動で行うと手間がかかります。開発時には、このプロセスを簡略化するために、ts-nodetsxのような TypeScript ファイルをコンパイルせずに直接実行できるツールを利用すると便利です。

tsxをインストールします。

$ npm install tsx --save-dev

package.jsonのscriptsに記載します。

package.json
{
  "name": "typescript-compile",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
+   "dev": "tsx watch src/index.ts"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "typescript": "^5.6.3"
  },
  "devDependencies": {
    "tsx": "^4.19.2"
  }
}

src/index.tsファイルの中身は以下です。

src/index.ts
const greet = (name: string): string => {
  return `Hello, ${name}!`;
};

const name = "TypeScript";
console.log(greet(name));

実行します。

$ npm run dev

ターミナルにHello, TypeScript!が表示されました。

src/index.tsファイルの中身を以下のように変更してみます。

src/index.ts
const greet = (name: string): string => {
- return `Hello, ${name}!`;
+ return `こんにちは, ${name}!`;
};

const name = "TypeScript";
console.log(greet(name));

変更を保存すると、リアルタイムでこんにちは, TypeScript!と表示されました。

まとめ

  • TypeScript は開発用のコードであり、そのままでは Node.js で実行できないため、JavaScriptに変換(コンパイル)する必要がある。
  • tsconfig.json とは TypeScript から JavaScript にコンパイルするための設定ファイル
  • 開発時には、このプロセスを簡略化するために、tsxのような TypeScript ファイルをコンパイルせずに直接実行できるツールを利用すると開発効率が上がる。

既存のプロジェクトに途中から入っているとなんとなくで TypeScript 開発ができてしまうのでしっかりと理解する良い機会になりました。(間違っていたら教えてください...)
次回はCommonJSとESModulesについて書きたいと思います!

Discussion