TypeScriptとNode.jsの組み合わせは、型安全なサーバーサイド開発を実現する強力な選択肢として注目を集めています。本記事では、実践的な例を交えながら、TypeScriptをNode.jsプロジェクトで効果的に活用する方法を解説します。

TypeScriptとNode.jsの基本セットアップ

まず、新規プロジェクトでTypeScriptを使用するための基本的なセットアップ手順を見ていきましょう。

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

続いて、`tsconfig.json`を作成します:

{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist"
  },
  "include": ["src/**/*"]
}

実践的な型定義の活用例

APIレスポンスの型定義

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

async function getUser(id: number): Promise<User> {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
}

Express.jsでの型活用

import express, { Request, Response } from 'express';

interface CustomRequest extends Request {
  user?: {
    id: string;
    role: string;
  }
}

app.get('/profile', (req: CustomRequest, res: Response) => {
  const user = req.user;
  if (!user) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  return res.json({ userId: user.id, role: user.role });
});

データベース操作での型安全性

interface DBConfig {
  host: string;
  port: number;
  database: string;
  username: string;
  password: string;
}

class Database {
  private config: DBConfig;

  constructor(config: DBConfig) {
    this.config = config;
  }

  async connect(): Promise<void> {
    // データベース接続処理
  }
}

エラーハンドリングと型安全性

カスタムエラークラスの実装例:

class ApplicationError extends Error {
  constructor(
    public statusCode: number,
    message: string
  ) {
    super(message);
    this.name = 'ApplicationError';
  }
}

function handleError(error: unknown) {
  if (error instanceof ApplicationError) {
    // 型安全なエラーハンドリング
    console.error(`${error.statusCode}: ${error.message}`);
  } else {
    console.error('Unknown error occurred');
  }
}

ベストプラクティスとTips

1. 型推論の活用

- 可能な限り型推論を活用し、冗長な型注釈を避ける

- 複雑な型の場合は明示的な型定義を使用

2. 型ガード

function isString(value: unknown): value is string {
  return typeof value === 'string';
}

3. Utility Types

type UserPartial = Partial<User>;
type UserReadOnly = Readonly<User>;

4. 環境変数の型安全な処理

interface Env {
  NODE_ENV: 'development' | 'production';
  PORT: number;
  API_KEY: string;
}

const env: Env = {
  NODE_ENV: process.env.NODE_ENV as 'development' | 'production',
  PORT: parseInt(process.env.PORT || '3000', 10),
  API_KEY: process.env.API_KEY || '',
};

TypeScriptとNode.jsの組み合わせは、開発効率の向上とバグの早期発見に大きく貢献します。型システムを適切に活用することで、より保守性の高い堅牢なアプリケーションを構築することができます。

継続的な学習と実践を通じて、TypeScriptの機能を最大限に活用し、高品質なNode.jsアプリケーションの開発を目指しましょう。