Express/Node.jsでTypeScriptを使ってみる

f:id:k-kty:20190213160011p:plain

最近、バックエンド開発でNode.jsを用いています。 JavaScriptは仕様がどんどん良くなってきているし、コールバックを用いた非同期処理も個人的には好きです。

しかしコードベースが大きくなると「型があればなあ...」と思うこともしばしば。 そこでTypeScriptに足を突っ込んでみることにしました。

そのときの記録の一部として、TypeScript + Node.js/ExpressでWebバックエンドの開発を始める方法を紹介します。

TypeScriptの文法・言語の機能についてはあまり触れません。(それらについては以下が参考になります。)

準備

npmプロジェクトを作成する

npm init を用いるなどして、package.jsonを作成します。

TypeScriptをインストール

$ npm i typescript --save-dev

JavaScriptからTypeScriptへのコンパイルに必要です。

TypeScriptの設定ファイルを作成

以下のような内容をtsconfig.jsonという名前で保存します。

{
  "compilerOptions": {
    "target": "es5",
    "outDir": "dist",
    "strict": true
  },
  "include": [
    "src/**/*",
  ]
}

軽く説明すると、このようになります。

  • target で、「どの仕様に対応したJavaScriptのコードをコンパイルによって生成するか」を指定しています。ここではES5を指定しています。
  • outDir で、コンパイル後のコードを保存するディレクトリを指定します。
  • strict をtrueにすることで、いろいろなTypeScriptのチェック機構が有効になります。
  • include で、コンパイルの対象にしたいファイル群を指定します。

expressとその「型定義ファイル」をインストール

$ npm i express --save
$ npm i @types/express --save-dev

このようにパッケージと一緒に型定義ファイルもインストールすることで、そのパッケージの関数やオブジェクトを使うときにもTypeScriptの型チェックを利用できるようになります。

ts-nodeをインストール

$ npm i ts-node --save-dev

これにより、node コマンドでJavaScriptコードを実行できるように、ts-node コマンドでTypeScriptコードを実行できるようになります。 ts-nodeは、「tscを用いてTypeScriptのコードをJavaScriptへコンパイルし、それをnodeで実行する」ということをしてくれています。 開発中に使うと便利です。なお、本番環境での仕様は推奨されていません。

実行スクリプトを追加

package.jsonの scripts の中身を以下のように書き換えます。

{
  "build": "tsc",
  "start": "node dist/index.js",
  "dev": "ts-node src/index.ts"
}

npm run build でTypeScriptのコードをコンパイルし、npm run start でそのJavaScriptコードを実行できるようになります。 npm run dev はその2つを組み合わせたことをやってくれますが、開発中のみ利用します。

Hello, Worldしてみる

コード

src/index.ts

import app from './app';

app.listen(process.env.PORT || 3000);

src/app.ts

import express from 'express';
import routes from './routes';

const app = express();

app.use('/', routes);

export default app;

src/routes.ts

import express from 'express';

const router = express.Router();

router.get('/', (req, res, next) => {
  res.send('Hello, World');
});

export default router;

起動

以下のコマンドでサーバーが起動します。

$ npm run dev

以下のように、きちんと動いていることがわかります。

$ curl http://localhost:3000/
Hello, World

テストをする

supertest を用いて、エンドポイント単位のテストをしてみます。

準備

supertestのインストール

supertestは、Node.jsのHTTPサーバーをテストするためのライブラリです。 型定義ファイルも同時にインストールします。

$ npm i supertest @types/supertest --save-dev

参考: https://github.com/visionmedia/supertest

mochaのインストール

mochaは、テストのためのフレームワークです。 下のコードに出てくる describe とか it とかいう関数はmochaが提供しているものです。 やはり、型定義ファイルも同時にインストールします。

$ npm i mocha @types/mocha --save-dev

参考: https://mochajs.org/

実行スクリプトを追加

package.json内の scripts に以下を追加します。 これにより、 npm run test でテストを実行できるようになります。

"test": "mocha --require ts-node/register test/**/*.ts"

--require ts-node/register により、JavaScriptによってコンパイルすること無くテストを実行できます。

コード

test/routes.ts

とても簡単なものです。

import request from 'supertest';
import 'mocha';

import app from '../src/app';

describe('ルーティング', () => {
  describe('/', () => {
    it('ステータスコード200を返す', async () => {
      await request(app)
        .get('/')
        .expect(200);
    });
  });
});

import mochadescribeit を使うために必要です。

実行

$ npm run test
  ルーティング
    /
      ✓ ステータスコード200を返す
  1 passing (37ms)

テストが通りました。

ビルド・実行する

本番環境で実行する際には、JavaScriptにコンパイル(ビルド)して、その結果生成されたファイルをNodeで実行する必要があります。 このための準備はすでにできていて、以下のスクリプトを実行するだけで大丈夫です。

$ npm run build
$ npm start