Help us understand the problem. What is going on with this article?

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

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 で手元の適当なコードを動かしたいときから、バッチ等でゴリゴリ動かしたいときまで簡単に対応できます。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした