LoginSignup
193
115

More than 3 years have passed since last update.

ts-node で TypeScript + node をサクッと実行する

Posted at

node でさっくりと TypeScript を実行したいときに、babel なり webpack なりで transpile して実行するのは不便です。しかも型が考慮されなくなってしまいますね。

そういうときは ts-node を使うことで、バベってファイルを生成してから食わせずとも、そのまま実行できるので手軽です。型も考慮されます。

使い方

さっくりと依存を追加します:

npm install --save typescript ts-node

tsconfig.json もついでに生成しておきます:

> ./node_modules/.bin/tsc --init

message TS6071: Successfully created a tsconfig.json file.

試しに適当なコードを書いてみます:

src/main.ts
const main = () => {
    console.log('It works!');
};

main();

動かしてみます:

> ./node_modules/.bin/ts-node src/main.ts

It works!

いい感じにすぐ実行されました。

もちろん型が誤っている場合もきちんとエラーになりますし、元のファイルの情報が表示されます:

src/main.ts
const main = (str: string) => {
    console.log('It works!');
};

main(1111);
TSError: ⨯ Unable to compile TypeScript:
src/main.ts:5:6 - error TS2345: Argument of type '1111' is not assignable to parameter of type 'string'.

5 main(1111);
       ~~~~

:thumbsup:

エイリアス

import some from '../../a/b.ts' とかになってややこしいので、パスのエイリアスを登録しておくことが結構あると思います:

tsconfig.json
{
  "compilerOptions": {
    // ...
    "baseUrl": "./",
    "paths": {
      "#/*": ["src/*"]
    },
    // ...
  }
}

この例では

src/x.ts
import some from '#/a/b.ts';
// <=> import some from './a/b.ts';
src/i/j/k.ts
import some from '#/a/b.ts';
// <=> import some from '../../a/b.ts';

となります。捗りますね。

これで import するスクリプトの階層にかかわらず、ソースルートディレクトリからのパスとして記述できるので、すっきりとしてわかりやすくなります。VSCode でもエイリアスが効いていい感じです。

Vue でも @/components/a.ts で参照できるようなエイリアスになってますが、似たような感じですね。 (あれは webpack のエイリアスのようですが)。


例として次のようなファイル構成にしてみましょう:

src/mod-a/build.ts
export default (): string => 'mod-a';
src/mod-b/repeat.ts
import build from '#/mod-a/build';

export default (number: number): string => {
    let queue = [];
    const value = build();
    for (let i = 0; i < number; ++i) {
        queue.push(value);
    }

    return queue.join(' | ');
}
src/main.ts
import repeat from "#/mod-b/repeat";

const main = () => {
    console.log(repeat(5));
};

main();

さて、これでエイリアスを使って読み込めたので
実行してみたいと思います:

> ./node_modules/.bin/ts-node src/main.ts

Error: Cannot find module '#/mod-b/repeat'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:581:15)
    at Function.Module._load (internal/modules/cjs/loader.js:507:25)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:22:18)
    at Object.<anonymous> (/Users/user/Sandbox/my-ts-project/src/main.ts:1:1)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Module.m._compile (/Users/user/Sandbox/my-ts-project/node_modules/ts-node/src/index.ts:473:23)
    at Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/Users/user/Sandbox/my-ts-project/node_modules/ts-node/src/index.ts:476:12)
    at Module.load (internal/modules/cjs/loader.js:599:32)

しかしながら、これは import が解決できずエラーになります。なぜでしょうか。

この問題は
tsconfig-paths を追加して、require してあげることで解決できます:

npm install --save tsconfig-paths
> ./node_modules/.bin/ts-node --files -r tsconfig-paths/register src/main.ts

mod-a | mod-a | mod-a | mod-a | mod-a

tsconfig-pathsrequire してあげることで、tsconfig.json で定義したエイリアスで import を解決できるようになりました。

ただ、毎回入れるのは面倒なので package.jsonscripts に追加して npm start 一発で実行できるようにすると楽でいいです:

package.json
{
  // ...
  "scripts": {
    "start": "ts-node --files -r tsconfig-paths/register",
    "test": "echo \"Error: no test specified\" && exit 1"
  }
}
npm start src/main.ts

:thumbsup:

型定義

自分で型定義 (*.d.ts) を持っている場合は、これも tsconfig.json に追加します:

tsconfig.json
{
  "compilerOptions": {
    // ...
    "typeRoots": ["./src/types"],
    // ...
}

テスト

テストに関しては別エントリで記述しました。同じくバベらずとも ts-jest を使うことで型を活かしながら簡単にテストができます:

👉 TypeScript のテストを Jest (ts-jest) でやってみる


これで TypeScript で手元の適当なコードを動かしたいときから、バッチ等でゴリゴリ動かしたいときまで簡単に対応できます。

193
115
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
193
115