アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

ts-node を試す

作業を効率化するためにちょっとしたスクリプトを書くことがある。その際いつもプログラミング言語と実行環境に Node.js を採用していたのだが、これを TypeScript 化したくなった。とはいえ小規模なスクリプト程度で実行前にコンパイルするのは面倒。なのでこれらを自動処理してくれるという TypeStrong/ts-node を試してみた。

環境構築

スクリプト実行用のプロジェクトを作成する。適当なディレクトリー内で npm init を実行して package.json を生成、その後に TypeScript 設定ファイル tsconfig.json とスクリプト本体の index.ts を用意。

.
├── index.ts
├── package.json
└── tsconfig.json

必要最小の npm をインストール。

$ npm i ts-node typescript @types/node

それぞれの役割をまとめる。

npm 役割
ts-node 指定された TypeScript ファイルをコンパイルして実行するための CLI ツール。
typescript TypeScript コンパイラー。
@types/node Node.js 由来の機能やモジュールに対する型情報。

ts-config.json を定義。現時点で最新の Node.js 12 系を想定して target を ES2017、チェック系は私の好みで厳しくしてある。雑なスクリプトなら noImplicitAny とか strictNullChecksfalse でもよいだろう。

{
  "compilerOptions": {
    "module": "commonjs",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "target": "es2017",
    "noImplicitAny": true,
    "strictNullChecks": true,
    "moduleResolution": "node",
    "declaration": true,
    "sourceMap": false,
    "outDir": "dist",
    "baseUrl": ".",
    "paths": {
      "*": ["node_modules/*"]
    }
  }
}

プロジェクトのローカルにある ts-node でスクリプトを実行させるため、コマンドを package.jsonnpm-scripts へ定義する。諸々、含めた全体は以下。

{
  "name": "my-tool",
  "version": "1.0.0",
  "description": "My tool.",
  "author": "akabeko",
  "license": "UNLICENSED",
  "private": true,
  "scripts": {
    "exec": "ts-node index.ts"
  },
  "dependencies": {
    "@types/node": "^12.6.8",
    "ts-node": "^8.3.0",
    "typescript": "^3.5.3"
  }
}

これで npm run exec を実行すれば index.tsts-node が自動的にコンパイル & 実行してくれる。タイプ量を減らしたければ

{
  "scripts": {
    "start": "npm run exec",
    "exec": "ts-node index.ts"
  }
}

として npm start で実行するのもよいだろう。starttest などは npm-scripts に予約されたコマンドで npm runrun を省略できる。

コマンドライン引数

スクリプトに対して動的に引数を与えて振る舞いを変えたくなった場合、どうすればよいか。これは npm-scripts 内へ指定したものをそのまま ts-node 経由でスクリプトに渡せる。

{
  "scripts": {
    "exec": "ts-node index.ts --foo"
  }
}

しかしこの方法だと引数を分岐させるために npm-scripts を修正するか複数定義しなければならず面倒。そのため npm-scripts 自体へ渡された引数を指定できるようにしたい。その方法は npm-run-script に紹介されている。

$ npm run exec -- --bar

このように -- を付けた後に引数を指定すれば、それを npm-scripts 側へそのまま渡してくれる。ちなみに npm-scripts 内でも引数を指定していた場合、

  1. npm-scripts 内の引数
  2. npm-scripts 実行時の引数

の順で渡される。例えば前述の npm-scripts と引数指定で

console.log(process.argv);

という TypeScript を実行したなら

$ npm run exec -- --bar

> my-tool@1.0.0 exec .../my-tool
> ts-node index.ts --foo "--bar"

[
  '.../my-tool/node_modules/.bin/ts-node',
  '.../my-tool/index.ts',
  '--foo',
  '--bar'
]

このような出力が得られる。

まとめ

最近はこんな感じの環境で簡易スクリプトを書いたり外部 npm 選定用の検証をおこなったりしてる。TypeScript としての機能を試すのにもよい。

ts-node などの依存はプロジェクト内で閉じているから、これを発展させてツール化した時も配布は簡単。プロジェクトのディレクトリー単位で渡して npm i すれば準備が完了する。実に便利。