公式のTypeScript-Node-Starterから始めてもいいが、依存が少し余分なので一から作ることにした。
コードはここ。
$ yarn add --dev typescript tslint tslint-microsoft-contrib jest ts-jest @types/jest
package.json
scriptsとテストフレームワークJestの設定を追加。
{
"devDependencies": {
...
"typescript": "^2.4.2"
},
"scripts": {
"start": "npm run build && node dist/app.js",
"build": "npm run lint && tsc",
"test": "jest --forceExit",
"lint": "tslint -c tslint.json -p tsconfig.json --type-check"
},
"jest": {
"transform": {
"^.+\\.ts$": "./node_modules/ts-jest/preprocessor.js"
},
"testRegex": "/test/.*\\.test\\.(ts|js)$",
"moduleFileExtensions": [
"ts",
"js"
],
"testEnvironment": "node"
}
}
tsconfig.json
公式のそのまま。
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"noImplicitAny": true,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"paths": {
"*": [
"node_modules/*",
"src/types/*"
]
}
},
"include": [
"src/**/*"
]
}
tslint.json
MSでも使われているらしいルールを使うことにする。 結構厳しくて console.log() なんかもエラーになるので必要に応じてruleを追加する。
{
"extends": "tslint-microsoft-contrib",
"rules": {
"no-console": [""],
"no-relative-imports": false,
"no-http-string": false,
"no-backbone-get-set-outside-model": false
}
}
使うパッケージをインストール
本体と型。
以前は型ファイルを持ってくるのにtsdとかtypingsが使われていたが 今はDefinelyTypedの内容が npmの@types/~に上がるようになった。
$ yarn add express
$ yarn add --dev @types/express
コードを書く
VSCodeだったらtslintプラグインがあるので入れる。tsとtslintをglobal installする必要がある。
import * as express from 'express';
/**
* GET /echo
* Return a string same as "say" query param.
*/
export function echoApi(req: express.Request, res: express.Response): void {
const query: { say: string } = <{ say: string }> req.query;
if (query.say === undefined) {
res.send(echo(query.say));
} else {
res.status(400).send('"say" query param is required');
}
}
/**
* return a string same as input
* @param say input (= output)
*/
export function echo(say: string): string {
return say;
}
テストを書く
superagentを使って HTTPサーバーのテストを行うsupertestを使う。
$ yarn add --dev supertest @types/supertest
import * as supertest from 'supertest';
import { app } from '../src/app';
import { echo } from '../src/echo';
let request: supertest.SuperTest<supertest.Test>;
beforeAll(() => {
request = supertest(app);
});
/**
* integration test
*/
describe('GET /echo', () => {
it('should return a string same as "say" query param', (): {} => {
const say: string = 'Aa 1あ';
return request
.get('/echo')
.query({ say: say })
.expect(200, say);
});
it('is bad request that "say" query param is not given', (): {} => {
return request
.get('/echo')
.expect(400);
});
});
/**
* unit test
*/
describe('echo', () => {
it('should return a string same as input', () => {
const say: string = 'Aa 1あ';
expect(echo(say)).toBe(say);
});
});
requestしたのをreturnするのを忘れるとテストが無条件で通ってしまうので注意。
$ npm test
...
PASS test/echo.test.ts
GET /echo
✓ should return a string same as "say" query param (34ms)
✓ is bad request that "say" query param is not given (4ms)
echo
✓ should return a string same as input (1ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 1.601s, estimated 2s
Ran all test suites.