TypeScriptは、JavaScriptに静的型付けを追加することで、開発者に多くの利点を提供します。特に、Express.jsのようなWebアプリケーションフレームワークと組み合わせることで、コードの安全性と保守性が向上します。本記事では、TypeScriptを使用してExpressアプリケーションを作成する際に役立つ型とその活用方法について、完全かつ包括的に解説します。
1. TypeScriptとExpressの基本
TypeScriptを使用するために、まずNode.js環境にTypeScriptをインストールし、設定する必要があります。これには、tsc
(TypeScriptコンパイラ)と、@types/express
という型定義を含むパッケージをインストールする必要があります。

bashnpm install typescript @types/node @types/express
インストールが完了したら、tsconfig.json
を設定して、TypeScriptコンパイラの設定を行います。この設定ファイルには、コンパイル対象や出力先のディレクトリなどが含まれます。
json{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "./dist"
}
}
2. Expressアプリケーションの作成
TypeScriptを使ってExpressアプリケーションを作成する際、基本的な型定義が既に用意されているため、型の補完やエラー検出を活用することができます。以下は、Expressサーバーを設定する最も基本的な例です。
typescriptimport express, { Request, Response } from 'express';
const app = express();
const port = 3000;
app.get('/', (req: Request, res: Response) => {
res.send('Hello, World!');
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});
この例では、Request
とResponse
の型をインポートし、req
およびres
オブジェクトに適切な型を付けることで、型安全なコードを作成しています。
3. ルートパラメータとクエリパラメータの型
Expressでは、ルートパラメータやクエリパラメータを簡単に扱うことができますが、TypeScriptではこれらのパラメータに対して型を定義することができます。
3.1 ルートパラメータ
ルートパラメータは、URLパスの一部として動的に値を渡す方法です。TypeScriptを使用することで、これらのパラメータに型を指定できます。
typescriptapp.get('/user/:id', (req: Request<{ id: string }>, res: Response) => {
const userId: string = req.params.id;
res.send(`User ID: ${userId}`);
});
上記のコードでは、req.params.id
がstring
型であることを明示しています。
3.2 クエリパラメータ
クエリパラメータはURLに追加される?key=value
の形式で渡されます。TypeScriptでこれらに型を指定する方法は以下の通りです。
typescriptapp.get('/search', (req: Request<{}, {}, {}, { query: string }>, res: Response) => {
const query: string = req.query.query;
res.send(`Search query: ${query}`);
});
ここでは、req.query.query
がstring
型であることを保証しています。
4. ミドルウェアの型定義
Expressでは、リクエスト処理の前後にミドルウェアを挿入することができます。TypeScriptでは、ミドルウェアに適切な型を付けることで、コードの安全性を向上させることができます。
typescriptconst logRequest: express.RequestHandler = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
};
app.use(logRequest);
このミドルウェア関数は、リクエストオブジェクト、レスポンスオブジェクト、next
関数を引数として受け取り、型が正しく指定されています。
5. 型定義の拡張
ExpressでTypeScriptを使用する際、型定義を拡張することができます。例えば、リクエストオブジェクトに追加のプロパティを付けたい場合、express
の型定義を拡張できます。
typescriptdeclare global {
namespace Express {
interface Request {
user?: { id: string; name: string };
}
}
}
これにより、req.user
プロパティに型を付け、アプリケーション全体で使用することができます。
typescriptapp.get('/profile', (req: Request, res: Response) => {
if (req.user) {
res.send(`User Profile: ${req.user.name}`);
} else {
res.send('No user found');
}
});
6. 非同期処理とエラーハンドリング
Expressアプリケーションで非同期処理を扱う際、TypeScriptの型定義を活用することで、非同期関数やエラーハンドリングを型安全に行うことができます。
typescriptapp.get('/data', async (req: Request, res: Response) => {
try {
const data = await fetchData(); // 非同期処理
res.json(data);
} catch (error) {
res.status(500).send('Server error');
}
});
非同期関数の結果に対して型を指定することができます。たとえば、fetchData
関数がPromise
を返す場合、data
の型はData
であることを明示できます。
7. 型の活用とテスト
TypeScriptを使うことで、Expressアプリケーションのテストもより堅牢になります。型によってリクエストやレスポンスの構造を事前に確認できるため、テストコードを作成する際にも役立ちます。
typescriptimport request from 'supertest';
import { app } from './app';
describe('GET /user/:id', () => {
it('should return the correct user', async () => {
const response = await request(app).get('/user/123');
expect(response.status).toBe(200);
expect(response.text).toBe('User ID: 123');
});
});
上記のテストコードでは、request
とapp
が型で適切に補完され、テストが正確に実行されることを保証します。
結論
TypeScriptを使ったExpressアプリケーションの開発は、型安全性を高めることで、バグの早期発見や保守性の向上に大いに役立ちます。型定義を適切に活用することで、開発者はより信頼性の高いコードを作成でき、エラーを未然に防ぐことができます。また、非同期処理やミドルウェアの型定義を適切に行うことで、アプリケーション全体の可読性と保守性が向上します。TypeScriptとExpressを組み合わせることで、堅牢で拡張性のあるWebアプリケーションを作成できるでしょう。