Ubuntuでローカルにexpress-generatorをインストールしてtypescriptで動かす

ネットにはグローバルにインストールする方法が多いのでローカルにインストールしてみる。

環境

まずはjavascriptで動かす

expressをインストールしたいフォルダに移動して、下記コマンドを実行

yarn add express-generator

さらに、アプリの雛形を作成(ローカルでインストールする場合、npxで実行する必要がある)

npx express <アプリ名>

指定したアプリ名のフォルダに移動して、下記コマンドを実行して足りないパッケージをインストール

yarn install

下記コマンドを実行してlocalhost:3000にアクセスして動作確認

yarn start

Express  
Welcome to Express

ブラウザでhttp://localhost:3000にアクセスして上記のように表示されていればOK。

TypeScriptに対応する

TypeScriptとExpressの型定義をインストール

yarn add --dev typescript @types/express

--devをつけるのはdevDependenciesにインストールしたいから。
typescriptや型定義ファイルは開発時に必要な依存関係なので、devDependenciesでOK。 引用元

tsconfig.jsonの作成

npx tsc --init

必要に応じてtsconfig.jsonを修正する

私は以下の3点を変更。

"target": "es2020",
"sourceMap": true,
"outDir": "./dist",

sourceMapは出力された JavaScript ファイルが実際に動作させるときに、デバッガーやその他のツールが元の TypeScript ソースファイルを表示できるようになります。 引用元
outDirを設定すると、.jsファイル(.d.tsや.js.mapファイルも同様)がこのディレクトリ内に出力されます。 元のソースファイルのディレクトリ構造は保存されます。引用元

なお、この時点だと、以下のような問題があると怒られるかもしれません。

構成ファイル 'XXX/XXX/tsconfig.json' で入力が見つかりませんでした。指定された 'include' パスは '["**/*"]' で、'exclude' パスは '["./dist"]' でした。

しかし、現時点では無視して構わないです。.tsファイルを作成していくとエラーが解消します。

app.jsで使われているモジュールの型宣言ファイルをインストールする

yarn add --dev @types/http-errors @types/cookie-parser @types/morgan

app.jsをapp.tsに変更、commonJSをES6な書き方に変更

以下のようにする。

import createError from 'http-errors';
import express, { ErrorRequestHandler } from 'express';
import cookieParser from 'cookie-parser';
import logger from 'morgan';

import { indexRouter } from './routes/index';
import { usersRouter } from './routes/users';

const app = express();

// view engine setup
app.set('views', 'views');
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static('public'));

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use((req, res, next) => {
  next(createError(404));
});

// error handler
const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
}
app.use(errorHandler);

export default app;

補足

最終行のexport default appは変更せずにmodule.exports = appのままでも良いかもしれません。 module.exportsのままの場合、トランスパイルしてもmodule.exportsのままであり、requireのみで問題ありません。
そのため、後述のwwwファイルを変更するときに、.defaultは不要です。

index.jsおよびusers.jsも.tsに変更、commonJSをES6な書き方に変更

  • index.ts
import express from 'express';
export const indexRouter = express.Router();

/* GET home page. */
indexRouter.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});
  • users.ts
import express, { Request, Response, NextFunction } from 'express';
export const usersRouter = express.Router();

/* GET users listing. */
usersRouter.get('/', (_req:Request, res:Response, next:NextFunction) => {
  res.send('respond with a resource');
});

パスを変更する

<アプリを作成したパス>/bin/wwwを以下のように修正する

var app = require('../dist/app').default;

export defaultをトランスパイルするとexports.defaultになるようです。
なので.defaultで読み込む必要があります。

トランスパイルする

npx tsc

yarn startしてlocalhost:3000localhost:3000/usersの動作を確認

respond with a resource

localhost:3000/usersにアクセスした場合、上記の一文だけが表示される。