今回は、express-generatorでプロジェクトを作成し、一部でTypeScriptを使用できるように環境構築を行います。
あらかじめ、npm、node、express-generatorをインストールしている前提で記載させていただきます。
環境
■ Nodeのバージョン
v14.14.0
■ 使用OS
MacOS Big Sur:バージョン11.6
■ 総合開発環境
Visual Studio Code
プロジェクト作成
% express --view=ejs types
create : types/
create : types/public/
create : types/public/javascripts/
create : types/public/images/
create : types/public/stylesheets/
create : types/public/stylesheets/style.css
create : types/routes/
create : types/routes/index.js
create : types/routes/users.js
create : types/views/
create : types/views/error.ejs
create : types/views/index.ejs
create : types/app.js
create : types/package.json
create : types/bin/
create : types/bin/www
change directory:
$ cd types
install dependencies:
$ npm install
run the app:
$ DEBUG=types:* npm start
作成したプロジェクトに移動します。
% cd types
パッケージインストール
Expressに必要なパッケージをインストールします。
% npm install
npm notice created a lockfile as package-lock.json. You should commit this file.
added 54 packages from 38 contributors and audited 55 packages in 2.921s
found 0 vulnerabilities
typescriptと@types/nodeをインストールします。
% npm install -D typescript @types/node
+ @types/node@16.11.6
+ typescript@4.4.4
added 2 packages from 42 contributors and audited 57 packages in 1.379s
found 0 vulnerabilities
tsconfig.jsonを生成します。
% npx tsc --init
message TS6071: Successfully created a tsconfig.json file.
ts-node、ts-node-dev、@types/express、@types/nodeをインストールします。
% npm install -D ts-node ts-node-dev @types/express @types/node
+ @types/node@16.11.6
+ @types/express@4.17.13
+ ts-node@10.4.0
+ ts-node-dev@1.1.8
added 68 packages from 118 contributors, updated 1 package and audited 125 packages in 9.451s
4 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
これで必要パッケージをインストールできました。
今回は、「www、app.js、index.js」の拡張子をtsに変更します。
変更後は「www.ts、app.ts、index.ts」になるようにします。
Visual Studio Codeなどの総合開発環境で確認すると、拡張子を変更したことによる型に関するエラーが出力されているので、修正します。
修正前
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) { //型エラー
res.render('index', { title: 'Express' });
});
module.exports = router;
修正後
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req:any, res:any, next:any) { //ここを修正
res.render('index', { title: 'Express' });
});
module.exports = router;
「www.ts、app.ts」も同様に修正します。
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('types:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val:any) { //ここを修正
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error:any) { //ここを修正
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req:any, res:any, next:any) { //ここを修正
next(createError(404));
});
// error handler
app.use(function(err:any, req:any, res:any, next:any) { //ここを修正
// 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');
});
module.exports = app;
ts-node-devを使用する
ts-node-devを使用できるように、package.jsonを編集します。
"scripts": {
"start": "node ./bin/www",
"dev": "ts-node-dev --respawn ./bin/www" //ここを追記
},
上記により、「npm run dev」コマンドでサーバーを起動できるようになりました。
最後に、サーバーを起動して「localhost:3000/」にアクセスします。
% npm run dev
> types@0.0.0 dev /Users/mizumotoshintarou/study/types
> ts-node-dev --respawn ./bin/www
[INFO] 23:08:21 ts-node-dev ver. 1.1.8 (using ts-node ver. 9.1.1, typescript ver. 4.4.4)
GET / 304 22.110 ms - -
GET /stylesheets/style.css 200 23.675 ms - 111
Expressの初期画面にアクセスできたかと思います。
Expressのプロジェクト作成時に、全てのファイルをTypeSciptで生成してくれるような機能は、私が検索した限りだと見当たりませんでした。
もし、もっと簡単な方法でTypeScript化できる方法をご存知の方がいらっしゃれば教えてください。
以上です。
ありがとうございました。