🐇

Express × TypeScript:実践例で見るメリット

2024/09/29に公開

概要

この記事では、Express アプリケーション開発において、TypeScript を使用することでえられる具体的なメリットについて解説します。

はじめに

Express は、Node.js 環境で Web アプリケーションを構築するためのシンプルなフレームワークです。従来、JavaScript を使用して開発されてきましたが、プロジェクトが大規模化するにつれて、型のない言語特有の問題が顕在化します。

この記事では、TypeScript を導入することで、これらの課題をどのように解決できるかを見ていきます。

JavaScript での Express アプリケーション

まずは、JavaScript でユーザー情報を取得するシンプルな API を実装してみます。

// index.js
const express = require('express');
const app = express();
const port = 3000;

app.get('/user/:id', (req, res) => {
  const userId = req.params.id;
  // ユーザーIDを数値に変換
  const numericUserId = parseInt(userId, 10);
  // データベースからユーザー情報を取得する処理(仮定)
  const user = getUserFromDatabase(numericUserId);
  res.send(user);
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

function getUserFromDatabase(id) {
  // ダミーデータ
  return { id, name: 'Alice' };
}

課題点

  • 型チェックがないuserIdnumericUserId が期待通りの型かどうかを検証できない。
  • ランタイムエラーの可能性parseInt の結果が NaN になっても気づかない。
  • IDE のサポートが限定的reqres オブジェクトのプロパティやメソッドの補完が不十分。

TypeScript での Express アプリケーション

次に、同じアプリケーションを TypeScript で実装してみます。

// index.ts
import express, { Request, Response } from 'express';

const app = express();
const port: number = 3000;

interface User {
  id: number;
  name: string;
}

app.get('/user/:id', (req: Request, res: Response) => {
  const userId = Number(req.params.id);
  if (isNaN(userId)) {
    res.status(400).send('Invalid user ID');
    return;
  }
  const user: User = getUserFromDatabase(userId);
  res.json(user);
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

function getUserFromDatabase(id: number): User {
  return { id, name: 'Alice' };
}

変更点

  • 型定義の追加RequestResponseUser インターフェースを使用。
  • 型チェックの強化userId が数値であることを検証。
  • エラーハンドリング:無効なユーザーIDに対する適切なレスポンスを追加。
  • IDE の補完機能向上:メソッドやプロパティの候補が正確に表示される。

TypeScript を使うメリット

1. 型安全性によるバグの減少

TypeScript の型チェック機能により、開発中に潜在的なバグを早期に発見できます。以下、いくつか具体的な例をみていきましょう!

例1: 型の不一致を検出

app.get('/user/:id', (req: Request, res: Response) => {
  const userId: number = req.params.id; // エラー
  // TS2322: Type 'string' is not assignable to type 'number'.
});
  • 問題点req.params.idstring 型であり、直接 number 型の userId に代入できません。
  • 解決策Number() 関数を使用して型変換を行います。
const userId: number = Number(req.params.id);

例2: 存在しないプロパティへのアクセス

app.get('/user/:id', (req: Request, res: Response) => {
  const user = getUserFromDatabase(Number(req.params.id));
  res.send(user.fullName); // エラー
  // TS2339: Property 'fullName' does not exist on type 'User'.
});
  • 問題点User 型に fullName プロパティは存在しません。
  • メリット:存在しないプロパティへのアクセスを防止できます。

例3: 関数の戻り値の型チェック

function getUserFromDatabase(id: number): User {
  return { id, name: 'Alice', age: 30 }; // エラー
  // TS2322: Type '{ id: number; name: string; age: number; }' is not assignable to type 'User'.
});
  • 問題点User インターフェースに age プロパティは定義されていません。
  • メリット:関数の戻り値が期待する型と一致しているかチェックできます。

例4: パラメータの存在確認

TypeScript では、関数の引数が未定義の場合にエラーを出すことができます。

app.get('/user/:id', (req: Request, res: Response) => {
  const { id } = req.params;
  if (!id) {
    res.status(400).send('User ID is required'); // エラー
    // TS2532: Object is possibly 'undefined'.
  }
});
  • 問題点req.params.idundefined の可能性があることを警告。
  • 解決策:型ガードやデフォルト値を使用して対処。

2. 開発効率の向上と VS Code の補完機能

TypeScript を使用すると、VS Code などのエディタでの自動補完機能が強化され、コーディングが効率化します。

例: VS Code での補完

app.get('/user/:id', (req: Request, res: Response) => {
  res. // ←ここで補完候補が表示されます。たとえば... ↓↓↓
});

表示される補完候補の例

  • レスポンス送信メソッド
    • send(body?: any): Response
    • json(body: any): Response
    • sendFile(path: string): void
    • sendStatus(statusCode: number): Response
    • render(view: string, options?: object): void
  • ステータスコード設定
    • status(code: number): Response
    • statusCode: number
  • ヘッダー操作
    • set(field: string, value?: string | string[]): Response
    • get(field: string): string
    • header(field: string, value?: string | string[]): Response
    • append(field: string, value?: string | string[]): Response
  • Cookie 操作
    • cookie(name: string, value: string | object, options?: CookieOptions): Response
    • clearCookie(name: string, options?: CookieOptions): Response
  • コンテンツタイプ設定
    • type(type: string): Response
    • format(obj: object): Response
  • リダイレクト
    • redirect(status: number, url: string): void
    • redirect(url: string): void
  • その他
    • vary(field: string): Response
    • location(url: string): Response
    • links(links: object): Response

メリット

  • メソッドやプロパティの誤用を防止:存在しないメソッド名をタイポするリスクを低減。
  • 開発速度の向上:適切なメソッドを素早く選択できる。
  • ドキュメント参照の手間を削減:補完候補にメソッドの概要や型情報が表示される。

3. メンテナンス性の向上

型情報とインターフェースを使用することで、コードの意図や構造が明確になり、メンテナンスが容易になります。

例: インターフェースの活用

interface User {
  id: number;
  name: string;
  email: string;
}

function createUser(user: User): User {
  // ユーザー作成の処理
  return user;
}
  • メリット

    • 型定義による一貫性:プロジェクト全体で同じ User 型を使用することで、一貫性を保てます。
    • 変更時の影響範囲が明確User 型にプロパティを追加・変更した際、影響を受ける箇所が型チェックで検出されます。

4. 大規模開発での強み

プロジェクトが大規模になると、型のないコードはバグの温床になります。TypeScript はこれを解決します。

  • 一貫性の維持:型定義により、コード全体で一貫したデータ構造を維持できる。
  • リファクタリングの容易さ:型情報に基づいて、安全にコードの変更が可能。
  • チーム開発の効率化:型情報があることで、新しいメンバーも迅速にコードを理解できる。

TypeScript 環境のセットアップ

1. プロジェクトの初期化

mkdir my-express-app
cd my-express-app
npm init -y

2. 必要なパッケージのインストール

npm install express
npm install --save-dev typescript @types/express ts-node nodemon
  • typescript:TypeScript コンパイラ。
  • @types/express:Express の型定義ファイル。
  • ts-node:TypeScript を直接実行するツール。
  • nodemon:ファイル変更時に自動再起動するツール。

3. TypeScript の設定ファイル生成

npx tsc --init
  • tsconfig.json が生成されます。必要に応じて設定を調整。

4. スクリプトの追加

package.json に以下のスクリプトを追加します。

"scripts": {
  "start": "nodemon src/index.ts"
},

5. ソースコードの作成

src/index.ts を作成し、TypeScript 版のコードを記述。

6. アプリケーションの起動

npm run start
  • ブラウザで http://localhost:3000 にアクセスして動作確認。

まとめ

TypeScript を使用することで、Express アプリケーション開発において以下のメリットが得られます。

  • 型安全性の向上:具体的な例を通じて、ランタイムエラーを未然に防止。
  • 開発効率の向上:VS Code の補完機能でコーディングがスムーズに。
  • メンテナンス性の向上:コードの理解と変更が容易。
  • 大規模開発での強み:一貫性と信頼性の高いコードベースを維持。

JavaScript から TypeScript への移行は段階的に行うことも可能です。新規プロジェクトはもちろん、既存のプロジェクトでも部分的に導入することで、TypeScript の恩恵を受けることができます。

皆さんのプロジェクトでも TypeScript を活用し、より堅牢で保守性の高いアプリケーション開発を実現してください。

参考資料

Discussion