トランスパイルしたい(tsc)
$ npx tsc
$ npx tsc src/main.ts
$ npx tsc --watch
tscコマンドで、TypeScript(.ts)をJavaScript(.js)に変換するコマンドです。
npx経由で実行することが多いです。
設定ファイル(tsconfig.json)がある場合は、自動で読み込まれます。
インストールしたい(typescript)
$ npm install --save-dev typescript @types/google-apps-script
typescriptパッケージをdevDependenciesとして追加します。
@types/google-apps-scriptは、GASの型情報を使うための型定義パッケージです。
明示的なインポートは必要ありません(というか不可です)。
注釈
devDependenciesにある@typesパッケージはVS Codeが自動で認識して、補完/チェックしてくれるようです。
@types/google-apps-scriptの中身は、DriveAppやSpreadsheetAppなどのサービスごとに分かれた.d.tsファイルの集まりです。
それぞれのファイルの中では、GoogleAppsScript.DriveやGoogleAppsScript.Spreadsheetのように、
サービス名の名前空間(namespace)の中にFileやSheetといった型が定義されています。
1// GoogleAppsScript.Drive.File 型が返る
2const files: GoogleAppsScript.Drive.FileIterator = DriveApp.getFiles();
3
4// 変数に型注釈をつけたいときは GoogleAppsScript.<サービス名>.<型名> の形式で書く
5function processFile(file: GoogleAppsScript.Drive.File): void {
6 Logger.log(file.getName());
7}
DriveAppやSpreadsheetAppのようなグローバル変数自体も、
declare var DriveApp: GoogleAppsScript.Drive.DriveApp;のように、
この名前空間の型を指す形でグローバルに宣言されています。
そのためimportしなくても、DriveApp.createFile(...)のように直接呼び出すだけで型補完が効きます。
ヒント
具体的な型名がわからないときは、VS CodeでDriveApp.getFiles()のような呼び出しにカーソルを合わせ、
「定義へ移動」(Go to Definition)を使うと、対応する.d.tsファイルと型名を直接確認できます。
型チェックだけしたい(tsc --noEmit)
$ npx tsc --noEmit
rollupを使う構成では、実際のトランスパイル・バンドルは@rollup/plugin-typescriptが担当するため、
tsc単体でファイルを出力する必要はありません。
--noEmitを付けると、ファイル出力をせずに型チェックだけを実行できます。
rollup実行前のCIやコミット前のチェックとして使うと便利です。
型をつけたい
1// 変数の定義
2const 変数名: 型名 = 値
3
4// 関数の定義
5function 関数名(引数名: 型名): 戻り値の型名 {...}
: 型名で変数や関数の型を指定できます。
この型を使って、トランスパイルや静的解析で潜在的なエラーを検出します。
注釈
トランスパイルしたあとのJavaScriptには型の情報は残りません。
スクリプト設定したい(package.json)
{
"name": "...",
"scripts": {
"build": "tsc --noEmit",
"bundle": "rollup -c",
"bundle:watch": "rollup -c --watch",
"push": "clasp push",
"pull": "clasp pull",
"deploy": "npm run build && npm run bundle && npm run push",
"...": "..."
}
}
buildで型チェックのみ、bundleで実際のトランスパイル・バンドルを行います。
紛らわしいですが、GASの世界では「ビルド=型チェック」「バンドル=1ファイルへのまとめ」と役割を分けるのが定番のようです。
deployでは、型チェック→バンドル→GASへのアップロードの順に実行しています。
設定したい(tsconfig.json)
{
"compilerOptions": {
"target": "ES2020", // GAS V8対応
"module": "ESNext", // rollupでバンドル前提
"moduleResolution": "bundler",
"lib": ["ES2020"],
"rootDir": "src", // ソースコードのルート
"outDir": "gas", // 出力先ディレクトリ(型チェックのみなら未使用)
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true, // 厳格な型チェック
"skipLibCheck": true // 依存パッケージの型チェックをスキップ
},
"include": [
// トランスパイル対象
"src/**/*"
],
"exclude": [
// トランスパイル対象外
"node_modules",
"gas"
]
}
tsconfig.jsonでTypeScriptのトランスパイルの設定ができます。
GASのV8ランタイムはECMAScript2020相当の機能までサポートしているため、それに合わせた設定にしています。
ここではrollupでモジュールをバンドルし、
claspでデプロイする前提でサンプルを作成しました。
targetは、トランスパイルして出力されるJavaScriptのECMAScriptバージョンを指定するオプションです。
GAS V8ランタイムでは"ES2020"程度まで指定できます。
moduleは、トランスパイルするときに利用するモジュール形式を指定するオプションです。
rollupなどでバンドルする場合は"ESNext"を指定しておけばよさそうです。
注釈
モダンブラウザ向けにESModuleを使う場合は、"ES2015"や"ES2020"などを指定します。
Node.jsを使う場合は"CommonJS"を指定します。GASでは非対応です。
moduleResolutionは、importやrequireで指定されたモジュールの探し方を指定するオプションです。
rollupなどのバンドラーを使う場合は"bundler"を指定します。
注釈
outDirを省略すると、.jsは各.tsファイルと同じ場所に出力されます。
慣習的にoutDirにはdistがよく使われますが、
本ページではclaspの.clasp.jsonを置くディレクトリと合わせる意図で、あえてgasという名前にしています。
rollupでバンドルする構成ではtsc自体はファイルを出力しない(前述のtsc --noEmit)ので、
outDirはほとんど意味を持ちません。
skipLibCheckは、node_modulesにある型定義ファイル(.d.ts)の型チェックを省略するオプションです。
@types/google-apps-scriptなど、サードパーティの型定義に問題があっても自分のコードのチェックを止めないために有効にしておくと安心です。