📻

[三感記事]ts-nodeをHello Worldから始める入門ガイド

2024/09/13に公開

1. イントロダクション

TypeScriptとNode.jsを組み合わせたts-nodeは、TypeScriptをトランスパイルせずに直接実行できる強力なツールです。本チュートリアルでは、基本的なts-nodeプロジェクトの設定から、実践的なアプリケーションの構築、さらには高度な使用法まで、初心者から中級者まで幅広く解説します。

1.1 対象読者

  • Node.jsの基本を理解している初心者開発者
  • TypeScriptを学び始めたばかりの方
  • ts-nodeを使ってプロジェクトを始めたい方

1.2 チュートリアルのゴール

  1. ts-nodeプロジェクトの基本的なセットアップ方法を理解する
  2. 必要な依存関係とその役割を学ぶ
  3. 実践的なTypeScriptアプリケーションを作成し実行する
  4. 環境変数の使用方法を学ぶ
  5. デバッグ技術を習得する
  6. 高度なts-nodeの設定とパフォーマンス最適化を理解する

ちなみにこの記事について

この記事は 「三感記事」 スタイルで書かれています。以下の3つの感覚を通じて学びを深めましょう。

📕 読む感 => 基礎知識の理解

テキストを通じて、概念や理論をお伝えします。

🔍 見る感 => 視覚からの理解

図表やアニメーションを使って複雑な概念を視覚化します。

💻 触れる感 => 実践による理解

実際に操作しながら学びます。

2. ts-nodeとは?

ts-nodeは、TypeScriptをNode.js上で直接実行するためのツールです。通常、TypeScriptコードをJavaScriptにコンパイルしてからNode.jsで実行する必要がありますが、ts-nodeを使用することで、この手順を省略できます。

以下の図は、通常のTypeScript実行フローとts-nodeを使用した場合の違いを示しています:

2.1 ts-nodeの主な利点

  1. 開発の迅速化: コンパイルのステップを省略することで、開発-テストサイクルが短縮されます。
  2. TypeScriptの恩恵: 型チェックやモダンな言語機能を利用しながら、Node.jsの豊富なエコシステムにアクセスできます。
  3. デバッグの容易さ: ソースマップが自動的に生成されるため、TypeScriptコードを直接デバッグできます。
  4. 設定の簡素化: 別途コンパイル用の設定を管理する必要がありません。

2.2 ts-nodeの動作原理

ts-nodeは内部で以下のような処理を行っています:

  1. TypeScriptコードを読み込む
  2. TypeScriptコンパイラ(tsc)を使用して、メモリ上でJavaScriptにトランスパイル
  3. 生成されたJavaScriptコードをNode.jsのruntimeに渡して実行

この過程で、ts-nodeは必要に応じてキャッシュを利用し、パフォーマンスを向上させています。

3. ts-nodeプロジェクトの構築

それでは、ts-nodeプロジェクトを実際に構築していきましょう。

3.1 プロジェクトの初期化

まず、新しいディレクトリを作成し、npmプロジェクトを初期化します。

mkdir my-ts-node-project
cd my-ts-node-project
npm init -y

このコマンドにより、package.jsonファイルが生成されます。このファイルはプロジェクトの設定や依存関係を管理するために使用されます。

3.2 必要な依存関係のインストール

以下のコマンドで依存関係をインストールします。

npm install typescript ts-node @types/node

各パッケージの役割は以下の通りです:

  • typescript: TypeScriptコンパイラとコア言語サービス
  • ts-node: TypeScriptを直接実行するためのツール
  • @types/node: Node.jsの型定義ファイル

これらのパッケージをdevDependenciesとしてインストールすることもできます:

npm install --save-dev typescript ts-node @types/node

devDependenciesとしてインストールすると、本番環境にはこれらのパッケージが含まれません。これにより、デプロイされるアプリケーションのサイズを小さく保つことができます。

3.3 TypeScriptの設定

次に、TypeScriptの設定ファイルtsconfig.jsonを作成します。

npx tsc --init

生成されたtsconfig.jsonファイルを以下のように編集します。

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "**/*.spec.ts"]
}
tsconfig.jsonの説明

以下は、tsconfig.jsonの設定項目を表形式でまとめた解説です。

設定項目 説明
compilerOptions.target ES2020 コンパイルされたJavaScriptのターゲットバージョンを指定します。この場合、ECMAScript 2020に対応。
compilerOptions.module commonjs モジュールシステムを指定します。この場合、Node.jsで使われるCommonJS形式が指定されています。
compilerOptions.strict true TypeScriptの全ての厳格モード(型チェックなど)を有効にします。
compilerOptions.esModuleInterop true require形式のインポートとES Moduleのインポートを互換性を持たせます。
compilerOptions.skipLibCheck true ライブラリファイルの型チェックをスキップします。コンパイル時間の短縮に役立ちます。
compilerOptions.forceConsistentCasingInFileNames true ファイル名の大文字小文字の違いによるエラーを防ぐために、一貫した大文字小文字のファイル名を強制します。
compilerOptions.outDir ./dist コンパイル後のJavaScriptファイルを出力するディレクトリを指定します。この場合、distフォルダに出力。
include ["src/**/*"] コンパイル対象のファイルを指定します。この場合、srcディレクトリ内の全てのファイルが対象になります。
exclude ["node_modules", "**/*.spec.ts"] コンパイル対象から除外するファイルを指定します。ここでは、node_modulesフォルダとテストファイルが除外されています。

この表を参考に、tsconfig.jsonの各設定項目が何を意味するかを理解できます。これにより、プロジェクトの構成や動作のカスタマイズが容易になります。

3.4 プロジェクト構造

次に、以下のようなプロジェクト構造を作成します。

my-ts-node-project/
│
├── src/
│   ├── index.ts
│   └── utils/
│       └── greeting.ts
│
├── package.json
├── tsconfig.json
└── .gitignore

この構造について詳しく説明します:

  • src/: ソースコードを格納するディレクトリ
    • index.ts: アプリケーションのエントリーポイント
    • utils/: ユーティリティ関数を格納するディレクトリ
      • greeting.ts: 挨拶関連の関数を定義するファイル
  • package.json: プロジェクトの設定とDependencyを管理するファイル
  • tsconfig.json: TypeScriptの設定ファイル
  • .gitignore: Gitの管理対象外とするファイルを指定するファイル

この構造は、小規模から中規模のプロジェクトに適しています。プロジェクトが大きくなるにつれて、より細かくディレクトリを分割することもあります。

3.5 アプリケーションの作成

まず、src/utils/greeting.tsファイルを作成し、以下のコードを追加します。

export function greet(name: string): string {
  return `Hello, ${name}! Welcome to ts-node.`;
}

このgreet関数は、引数として渡された名前を使用して挨拶文を生成します。TypeScriptの型注釈を使用することで、引数nameが文字列であることと、戻り値が文字列であることを明示しています。

次に、src/index.tsファイルを作成し、以下のコードを追加します。

import { greet } from './utils/greeting';

function main() {
    const args = process.argv.slice(2);
    const name = args[0] || 'World';
    console.log(greet(name));
}

main();

このコードについて詳しく説明します:

  1. import { greet } from './utils/greeting';: greeting.tsからgreet関数をインポートします。
  2. main関数を定義し、アプリケーションのメインロジックをカプセル化します。
  3. process.argv.slice(2)を使用して、コマンドライン引数を取得します。
  4. 引数が提供されない場合は、デフォルト値として'World'を使用します。
  5. greet関数を呼び出し、結果をコンソールに出力します。

3.6 実行スクリプトの設定

次に、package.jsonファイルのscriptsセクションを以下のように編集します。

{
  "scripts": {
    "start": "ts-node src/index.ts",
    "build": "tsc"
  }
}

これらのスクリプトについて説明します:

  • start: ts-nodeを使用してsrc/index.tsを直接実行します。開発中に使用します。
  • build: TypeScriptコンパイラ(tsc)を使用してJavaScriptにコンパイルします。本番環境用のビルドに使用します。

3.7 ts-nodeの実行をプレビュー

アプリケーションを実行するには、以下のコマンドを使用します。

npm start

出力例:

引数を渡すこともできます。

npm start -- おぐま

出力例:

これらのコマンドは、package.jsonscriptsセクションで定義したスクリプトを実行しています。
--以降の引数は、スクリプトに渡されます。

GitHubアカウントを持ってる方は是非触ってみてください。

4. 高度なts-nodeの使用法

基本的なセットアップが完了したので、より高度なts-nodeの使用法について探っていきましょう。

4.1 環境変数の使用

実際の開発では、環境変数を使用してアプリケーションの設定を管理することが一般的です。ts-nodeプロジェクトでも環境変数を簡単に利用できます。

まず、dotenvパッケージをインストールします:

npm install dotenv

次に、プロジェクトのルートディレクトリに.envファイルを作成し、以下のように環境変数を定義します:

APP_NAME=MyTsNodeApp
GREETING_LANGUAGE=en

そして、src/index.tsファイルを以下のように更新します。

import dotenv from 'dotenv';
import { greet } from './utils/greeting';

dotenv.config();

function main() {
    const args = process.argv.slice(2);
    const name = args[0] || 'World';
    const language = process.env.GREETING_LANGUAGE || 'en';
    console.log(`App: ${process.env.APP_NAME}`);
    console.log(greetWithLanguage(name, language));
}

main();

また、src/utils/greeting.tsも以下の関数を追加します

export function greetWithLanguage(name: string, language: string = 'en'): string {
    const greetings: {[key: string]: string} = {
        en: 'Hello',
        ja: 'こんにちは',
        es: 'Hola'
    };
    const greeting = greetings[language] || greetings['en'];
    return `${greeting}, ${name}! Welcome to ts-node.`;
}

これにより、環境変数を使用して挨拶の言語を切り替えることができます。

4.2 デバッグ

ts-nodeプロジェクトのデバッグは、Visual Studio Codeを使用すると非常に簡単です。

  1. VSCodeで.vscode/launch.jsonファイルを作成し、以下の内容を追加します:
{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Debug ts-node",
            "runtimeArgs": ["-r", "ts-node/register"],
            "args": ["${workspaceFolder}/src/index.ts"],
            "env": {"TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json"},
            "sourceMaps": true,
            "cwd": "${workspaceFolder}",
            "protocol": "inspector",
            "console": "integratedTerminal"
        }
    ]
}
  1. ブレークポイントを設定し、F5キーを押してデバッグを開始します。

これにより、TypeScriptコードを直接デバッグでき、変数の値の確認や実行フローの追跡が可能になります。

4.3 パフォーマンス最適化

ts-nodeは開発時には非常に便利ですが、大規模なプロジェクトではパフォーマンスが問題になることがあります。以下は、パフォーマンスを向上させるためのいくつかのテクニックです:

  1. トランスパイルのみモード: 型チェックを無効にし、トランスパイルのみを行うモードを使用します。
ts-node --transpile-only src/index.ts
  1. swcを使用: @swc/core@swc/registerをインストールし、高速なトランスパイルを実現します。
npm install --save-dev @swc/core @swc/register

そして、以下のコマンドで実行します:

node -r @swc/register src/index.ts
  1. キャッシュの活用: ts-nodeは自動的にキャッシュを利用しますが、明示的に有効にすることもできます。
TS_NODE_CACHE=true ts-node src/index.ts

4.4 モジュールエイリアスの設定

大規模なプロジェクトでは、絶対パスのインポートを使用すると、コードの可読性が向上します。ts-nodeでもモジュールエイリアスを設定できます。

  1. まず、tsconfig.jsonに以下の設定を追加します:
{
  "compilerOptions": {
    // ... 他の設定 ...
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}
  1. tsconfig-pathsパッケージをインストールします:
npm install --save-dev tsconfig-paths
  1. package.jsonのスクリプトを以下のように更新します:
{
  "scripts": {
    "start": "ts-node -r tsconfig-paths/register src/index.ts"
  }
}

これにより、src/utils/greeting.tsを以下のようにインポートできるようになります:

import { greet } from '@/utils/greeting';

4.5 テストの実装

ts-nodeプロジェクトでのテスト実装も簡単です。ここでは、Jestを使用したテストの例を示します。

  1. 必要なパッケージをインストールします:
npm install --save-dev jest ts-jest @types/jest
  1. jest.config.jsファイルを作成し、以下の内容を追加します:
module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
};
  1. src/utils/greeting.test.tsファイルを作成し、テストを記述します:
import { greet } from './greeting';

describe('greeting function', () => {
  it('should return correct greeting in English', () => {
    expect(greet('John', 'en')).toBe('Hello, John! Welcome to ts-node.');
  });

  it('should return correct greeting in Japanese', () => {
    expect(greet('山田', 'ja')).toBe('こんにちは, 山田! Welcome to ts-node.');
  });
});
  1. package.jsonにテストスクリプトを追加します:
{
  "scripts": {
    // ... 他のスクリプト ...
    "test": "jest"
  }
}

これで、npm testコマンドを実行してテストを行うことができます。

4.6 実際の動きをプレビュー

理論を学ぶだけでなく、実際にコードを書いて試すことが大切です。そこで、GitHubのCodespacesを使って、すぐに体験できる開発環境を用意しました。
以下のボタンをクリックしてGitHubアカウントでログインすると、ブラウザ上でTypeScriptとts-nodeの開発環境がすぐに起動します。コードを編集して、リアルタイムで結果を確認できます。

Open in GitHub Codespaces

まとめ

このチュートリアルでは、ts-nodeを使ってTypeScriptプロジェクトをセットアップし、実践的なアプリケーションを作成する方法について学びました。さらに、高度な使用法、よくある問題とその解決方法、ベストプラクティスについても解説しました。

ts-nodeを使えば、開発が効率的になり、型安全性を保ちながら迅速にNode.jsアプリケーションを開発することが可能です。ここで学んだ技術を活用し、より堅牢で保守性の高いTypeScriptプロジェクトを構築していってください。

Discussion