TypeScriptで"SyntaxError: Unexpected token import"になったときの解決方法

昨日の記事を公開したところ、

blog.zuckey17.org

↓のように、

ライブラリと型定義のimportとで分けている必要はあるのか?

という指摘をいただきました。

const { createConnection } = require("mysql"); // ライブラリのimport
import { Connection, MysqlError } from "mysql"; // 型定義のimport

僕も実装をしている際に、以下のような書き方をしようとしましたが、

import * as mysql from "mysql";

トランスパイル後のjsを実行するとランタイムで以下のようなエラーが出てしまいました。

******/ts-mysql/src/index.ts:1
(function (exports, require, module, __filename, __dirname) { import * as mysql from 'mysql';
                                                              ^^^^^^

SyntaxError: Unexpected token import
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:607:28)
    at Module.m._compile (/Users/matsumura/dev/src/github.com/zuckeyM-17/ts-mysql/node_modules/ts-node/src/index.ts:400:23)
    at Module._extensions..js (module.js:654:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/Users/matsumura/dev/src/github.com/zuckeyM-17/ts-mysql/node_modules/ts-node/src/index.ts:403:12)
    at Module.load (module.js:556:32)
    at tryModuleLoad (module.js:499:12)
    at Function.Module._load (module.js:491:3)
    at Function.Module.runMain (module.js:684:10)

tsconfig.json

結論としては、tsconfig.jsoncompilerOptions中のmoduleの値をes2015からcommonjsに変更すると解決しました。

module

TypeScript公式のcompilerOptionsリファレンスにおいて、
moduleの項には、

target === "ES3" or "ES5" ? "CommonJS" : "ES6"

という記載がされています

トランスパイル先がES5やそれ以下の場合、CommonJSを使いましょうということですね。
今回は、サーバサイドで動かすということで、WebpackBabelなどを利用せず、Node.jsとして動かすという実装だったので、CommonJSを指定する必要があったようです。

Node.jsとES2015のmoduleのインポートの方法の違い

moduleES2015を利用するとそれでは普通に使える、import/exportの記法は、そのままスルーされる。 型定義のimport句については、TypeScriptのトランスパイル時の静的解析に使われるだけなので、ランタイム時には影響がなかった。

ということでした。
つまり、サーバサイドで動かすとしても、WebpackBabelをかませるなどすると、問題なく利用できるようです。
そちらを検討しても良いかもしれません。

まとめ

TypeScriptのみならず、JavaScriptにおいても、モジュール解決や、import/export、が実行環境などによってややこしいです。
また、環境設定などは公式や人の記事を見て動けばそのまま使ってしまっていたり、一度固まればあまり振り返る機会がなかったりしていました。
日頃からtsconfig.jsonや、webpack.config.jsなどなどもやもやしながら使っている部分があるので、もう少ししっかり学習する必要があると感じました。

今回のブログをかけたのは、昨日のブログにたいして指摘いただけたからです。
もしこのブログでも気になる部分がありましたらコメントやTwitterで指摘いただけるとうれしいです。

おまけ

TypeScriptを簡単に実行するために、ts-nodeという実行環境を利用しています。

npx ts-node 実行ファイル

とすると、TypeScriptを実行することができます。

しかしながら、この状態では、importが利用できません。
そのため、import/exportを利用したい場合は、以下のようにprojectオプションを付ける必要があります。

# --project の引数は、tsconfig.jsonへのパス
npx ts-node --project tsconfig.json 実行ファイル